import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.xalan.xpath.xdom.XercesLiaison;
import org.apache.xalan.xslt.*;
import org.apache.xerces.parsers.DOMParser;
import org.apache.xerces.dom.DocumentImpl;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
//--

/*
 * XML Edit - find a xml node by matching the contents of one of it's children 
 * If contents are null, return a form list of the childs contents to select from
 * attempt to delete a node based on the above and match tag to params and 
 * insert it as a new node at the old position.
 */
public class xe extends HttpServlet
{ 
	public String XDocRoot; // location of doc root in initArgs from zone.properties
	public String XAction; // full URL to this script for posting subsequent passes
	public String XDocName; // name on xml file to work on in XDocRoot
	public String XDocDir; // directory added to XDocRoot where XDocName is
	public String XMap; // if set to addamap will prompt for .map dir to be added to xdocroot
	public String XDad; // optional parent xml doc to touch upon successful edit
	public String XItem; // sub item to edit
	public String XPTag;   // tag to match on
	public String XData; // contents matching above tag ie: <XPTag>XData<XPTag> matches it's time to build a form
	public String XStyle; // name of xsl for editing single XItem along w/ <xmledit><xdoc>doc</xdoc><xitem>...</xmledit>
	public String Title = "Linus's XmlEditor Wiz"; // title of html pages
	public String XAct; // action of editor - deletion if equal to "del"
	public String XStyleDir; // docroot without xdir added

/*
 * Collect tbe necessaries
 */
	void getReqParams( HttpServletRequest req ) 
	{
		ServletContext context = this.getServletContext();
		XStyleDir = context.getInitParameter( "docroot" );
		XMap = req.getParameter( "xmap" );
		XDocDir = req.getParameter( "xdir" );
		if ( XDocDir != null )
		{
			XDocRoot = XStyleDir + XDocDir + "/";
		}
		else
		{
			XDocRoot = XStyleDir;
		}
		if ( XMap != null && !XMap.equals( "addamap" ))
		{
			if ( XDocDir != null )
				XDocRoot = XStyleDir + XDocDir + "/" + XMap + ".map/";
			else
				XDocRoot = XStyleDir + XMap + ".map/";
		}

  		XAction = context.getInitParameter( "xaction" ); 
		XDocName = req.getParameter( "xdoc" );
		XDad = req.getParameter( "xdad" );
		XItem = req.getParameter( "xitem" );
		XPTag = req.getParameter( "xptag" );
		XData = req.getParameter( "xdata" );
		XStyle = req.getParameter( "xstyle" );
		XAct = req.getParameter( "xact" );
	} // eo getReqParams

	/*
 	* build a node tree of our hidden form data and return it for the stylesheet to use
 	*/
	org.w3c.dom.Node addMyNodes( org.w3c.dom.Node nod )
	{
		Document doc = nod.getOwnerDocument();
		org.w3c.dom.Element root = null;
		org.w3c.dom.Element xitem = null;
		org.w3c.dom.Element xkid = null;

		root = doc.createElement( "page" );
		xkid = doc.createElement( "xmledit" );

		xitem = doc.createElement( "xdoc" );
		xitem.appendChild( doc.createTextNode( XDocName ));
		xkid.appendChild( xitem );

		xitem = doc.createElement( "xitem" );
		xitem.appendChild( doc.createTextNode( XItem ));
		xkid.appendChild( xitem );

		xitem = doc.createElement( "xptag" );
		xitem.appendChild( doc.createTextNode( XPTag ));
		xkid.appendChild( xitem );

		xitem = doc.createElement( "xdata" );
		xitem.appendChild( doc.createTextNode( XData ));
		xkid.appendChild( xitem );

		xitem = doc.createElement( "xstyle" );
		xitem.appendChild( doc.createTextNode( XStyle ));
		xkid.appendChild( xitem );

		if ( XDocDir != null )
		{
			xitem = doc.createElement( "xdir" );
			xitem.appendChild( doc.createTextNode( XDocDir ));
			xkid.appendChild( xitem );
		}
		if ( XDad != null )
		{
			xitem = doc.createElement( "xdad" );
			xitem.appendChild( doc.createTextNode( XDad ));
			xkid.appendChild( xitem );
		}
		if ( XAct != null )
		{
			xitem = doc.createElement( "xact" );
			xitem.appendChild( doc.createTextNode( XAct ));
			xkid.appendChild( xitem );
		}
		if ( XMap != null )
		{
			xitem = doc.createElement( "xmap" );
			xitem.appendChild( doc.createTextNode( XMap ));
			xkid.appendChild( xitem );
		}

		root.appendChild( nod );
		root.appendChild( xkid );
		root.normalize();
		return( root );
	}

/*
 *  get an XSLTProcessor interface object from the XSLTProcessorFactory
 */
	void applyXslToDom( org.w3c.dom.Node node, PrintWriter Out )
			throws java.io.IOException, 
				   java.net.MalformedURLException,
				   org.xml.sax.SAXException
	{
	   XSLTProcessor processor = XSLTProcessorFactory.getProcessor(new org.apache.xalan.xpath.xdom.XercesLiaison());
	   processor.process(new XSLTInputSource( node ), new XSLTInputSource( XStyleDir + XStyle ), new XSLTResultTarget( Out ));
	} 

/*
 * find our node tree, add our info and apply the xstyle sheet to it to produce the editor form 
 */
	public void editForm( org.w3c.dom.NodeList nodeListi, PrintWriter Out ) 
				throws java.io.IOException, 
					   java.net.MalformedURLException,
					   org.xml.sax.SAXException
	{
		int type;
		int x;
		String name;
		String val;
		org.w3c.dom.Node nodei;
		org.w3c.dom.Node nodej;

		for (int i=0; i < nodeListi.getLength(); i++ ) // for every xitem we are looking for
		{
			nodei = nodeListi.item(i);
			type = nodei.getNodeType();
			name = nodei.getNodeName();
			if ( type == 1 && name.equals( XItem ) && nodei.hasChildNodes() ) // check it's children
			{
				org.w3c.dom.NodeList childTagNodes = nodei.getChildNodes();
				for (int j=0; j<childTagNodes.getLength(); j++) 
				{
					nodej = childTagNodes.item(j);
					type = nodej.getNodeType();
					name = nodej.getNodeName();
					if ( type == 1 && name.equals( XPTag ) && nodej.hasChildNodes() ) // it's our key
					{
						org.w3c.dom.NodeList childnodes = nodej.getChildNodes(); // check it's data
						for (int k=0; k<childnodes.getLength(); k++) 
						{
							
							org.w3c.dom.Node childnode = childnodes.item(k);
							type = childnode.getNodeType();
							name = childnode.getNodeName();
							val = childnode.getNodeValue().trim();
							if ( type == 3 && name.equals( "#text" ) && val.equals( XData )) // nodej is it
							{
								Document doc = nodej.getOwnerDocument(); 
								org.w3c.dom.Node rotag = doc.createElement( "readonly" ); // flag our key item
								nodei.replaceChild( rotag, nodej );
								applyXslToDom( addMyNodes( nodei ), Out ); 
							}
						}
					}
				}
			}
		}
	} // eo editForm

/*
 * create the top of a form
 */
	void topOfForm( PrintWriter Out )
	{
		Out.println("<html><head><title>");
		Out.println( Title );
		Out.println("</title></head><body bgcolor=\"#FFFFFF\"><center><table border=\"0\" cellspacing=\"8\" cellpadding=\"8\">");
		Out.println("<tr><td><table border=\"1\" width=\"100%\"><tr><th align=\"center\">" + XItem + " Edit Wizard</th></tr></table></td></tr>");
		Out.println("<tr><td align=\"left\"><form  method=\"Post\" action=\"" + XAction + "\">");
	} // eo topOfForm

/*
 *  end of a form
 */
	void endOfForm( PrintWriter Out )
	{
		Out.println( "</form>" );
		Out.println( "</td></tr></table></center>" );
		Out.println( "<p /><a href=\"/emonster/index.xml\">Home</a>" );
		Out.println( "</body></html>" );
	} // eo endOfForm

/*
 *  xmap param is addamap present a form to get real dir
 */
	void selectXMap( PrintWriter Out )
	{
		File mapPath = new File( XDocRoot );
		ExtensionFilter mf = new ExtensionFilter( "map" );
		String[] mapDirs = mapPath.list( mf );

		topOfForm( Out );
		Out.println( "Select a map to use: </td></tr>" );
		Out.println( "<tr><td align=\"left\"><select name=\"xmap\" size=\"9\">" );
		for ( int i = 0; i < mapDirs.length; i++ )
		{
			Out.println("<option />" + mapDirs[ i ].substring( 0, mapDirs[ i ].length() - 4 ));
		}
		Out.println( "</select></td></tr>" );
		Out.println("<tr><td><table border=\"1\" width=\"100%\"><tr><th align-\"center\"><input type=\"submit\" value=\"Next &gt;&gt;\" /></th></tr></table></td></tr>"); 
		Out.println("<tr><td><input type=\"hidden\" name=\"xitem\" value=\"" + XItem + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xstyle\" value=\"" + XStyle + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xptag\" value=\"" + XPTag + "\" /></td></tr>");
		if ( XDocDir != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdir\" value=\"" + XDocDir + "\" /></td></tr>");
		}
		if ( XDad != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdad\" value=\"" + XDad + "\" /></td></tr>");
		}
		if ( XAct != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xact\" value=\"" + XAct + "\" /></td></tr>");
		}
		if ( XData != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdata\" value=\"" + XData + "\" /></td></tr>");
		}
		endOfForm( Out );
	}


/*
 *  xdoc param is empty present a form to fill it
 */
	void selectXDoc( PrintWriter Out )
	{
		File xmlPath = new File( XDocRoot );
		ExtensionFilter xf = new ExtensionFilter( "xml" );
		String[] xmlDirs = xmlPath.list( xf );

		topOfForm( Out );
		Out.println( "Select a " + XItem + " to edit: </td></tr>" );
		Out.println( "<tr><td align=\"left\"><select name=\"xdoc\" size=\"9\">" );

		for ( int i = 0; i < xmlDirs.length; i++ )
		{
			Out.println("<option />" + xmlDirs[ i ].substring( 0, xmlDirs[ i ].length() - 4 ));
		}

		Out.println( "</select></td></tr>" );
//		Out.println( "<tr><td>XDocRoot: " + XDocRoot + "</td></tr>" );
		Out.println("<tr><td><table border=\"1\" width=\"100%\"><tr><th align-\"center\"><input type=\"submit\" value=\"Next >>\" /></th></tr></table></td></tr>"); 
		Out.println("<tr><td><input type=\"hidden\" name=\"xitem\" value=\"" + XItem + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xstyle\" value=\"" + XStyle + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xptag\" value=\"" + XPTag + "\" /></td></tr>");
		if ( XMap != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xmap\" value=\"" + XMap + "\" /></td></tr>");
		}
		if ( XDocDir != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdir\" value=\"" + XDocDir + "\" /></td></tr>");
		}
		if ( XDad != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdad\" value=\"" + XDad + "\" /></td></tr>");
		}
		if ( XAct != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xact\" value=\"" + XAct + "\" /></td></tr>");
		}
		if ( XData != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdata\" value=\"" + XData + "\" /></td></tr>");
		}
		endOfForm( Out );
	}

/*
 *  xptag param is empty present a form to fill it
 */
	void selectXPTag( org.w3c.dom.NodeList nodeList, PrintWriter Out )
	{
		String name;
		int type;
		String val;
		org.w3c.dom.Node node;

		topOfForm( Out );
		Out.print("Select a tag to identify a single " + XItem + " by it's unique contents");
		Out.println(" with and one that is <b>not</b> the item you wish to edit:</td></tr>");
		Out.println("<tr><td align=\"center\"><select name=\"xptag\" size=\"9\">");

		node = nodeList.item(0);
		type = node.getNodeType();
		name = node.getNodeName();
		if ( type == 1 && name.equals( XItem ) && node.hasChildNodes() )
		{
			org.w3c.dom.NodeList childTagNodes = node.getChildNodes();
			for (int j=0; j<childTagNodes.getLength(); j++)
			{
				node = childTagNodes.item(j);
				type = node.getNodeType();
				name = node.getNodeName();
				if ( type == 1 && node.hasChildNodes() )
				{
					Out.println("<option />" + name );
				}
			}
		}
		Out.println("</select></td></tr>");
		Out.println("<tr><td><table border=\"1\" width=\"100%\"><tr><th align-\"center\"><input type=\"submit\" value=\"Next >>\" /></th></tr></table></td></tr>"); 
		Out.println("<tr><td><input type=\"hidden\" name=\"xdoc\" value=\"" + XDocName + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xitem\" value=\"" + XItem + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xstyle\" value=\"" + XStyle + "\" /></td></tr>");
		if ( XMap != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xmap\" value=\"" + XMap + "\" /></td></tr>");
		}
		if ( XDocDir != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdir\" value=\"" + XDocDir + "\" /></td></tr>");
		}
		if ( XDad != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdad\" value=\"" + XDad + "\" /></td></tr>");
		}
		if ( XAct != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xact\" value=\"" + XAct + "\" /></td></tr>");
		}
		endOfForm( Out );
	}

/*
 *  xdata param is empty present a form to fill it
 */
	void selectXData( org.w3c.dom.NodeList nodeList, PrintWriter Out )
	{
		String name;
		int type;
		String val;
		org.w3c.dom.Node node;

		topOfForm( Out );
		if ( XAct != null && XAct.compareTo((String)"del")== 0 )
			Out.println("Select a " + XItem + " to delete: </td></tr>");
		else
			Out.println("Select a " + XItem + " to edit: </td></tr>");
		Out.println("<tr><td align=\"left\"><select name=\"xdata\" size=\"9\">");

		for (int i=0; i < nodeList.getLength(); i++ ) // for every xitem we are looking for
		{
			node = nodeList.item(i);
			type = node.getNodeType();
			name = node.getNodeName();
			if ( type == 1 && name.equals( XItem ) && node.hasChildNodes() )
			{
				org.w3c.dom.NodeList childTagNodes = node.getChildNodes();
				for (int j=0; j<childTagNodes.getLength(); j++) 
				{
					node = childTagNodes.item(j);
					type = node.getNodeType();
					name = node.getNodeName();
					if ( type == 1 && name.equals( XPTag ) && node.hasChildNodes() )
					{
						org.w3c.dom.NodeList childnodes = node.getChildNodes();
						for (int k=0; k<childnodes.getLength(); k++) 
						{
							org.w3c.dom.Node childnode = childnodes.item(k);
							type = childnode.getNodeType();
							name = childnode.getNodeName();
							val = childnode.getNodeValue().trim();
							if ( type == 3 && name.equals( "#text" ) && !(val.equals("")) )
								Out.println("<option />" + val );
						}
					}
				}
			}
		}
		Out.println("</select></td></tr>");
		Out.println("<tr><td><table border=\"1\" width=\"100%\"><tr><th align-\"center\"><input type=\"submit\" value=\"Next >>\" /></th></tr></table></td></tr>"); 
		Out.println("<tr><td><input type=\"hidden\" name=\"xdoc\" value=\"" + XDocName + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xitem\" value=\"" + XItem + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xstyle\" value=\"" + XStyle + "\" /></td></tr>");
		Out.println("<tr><td><input type=\"hidden\" name=\"xptag\" value=\"" + XPTag + "\" /></td></tr>");
		if ( XMap != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xmap\" value=\"" + XMap + "\" /></td></tr>");
		}
		if ( XDocDir != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdir\" value=\"" + XDocDir + "\" /></td></tr>");
		}
		if ( XDad != null )
		{
			Out.println("<tr><td><input type=\"hidden\" name=\"xdad\" value=\"" + XDad + "\" /></td></tr>");
		}
		endOfForm( Out );
	}

/*
 * Check for empty params and build/display the appropriate form
 */
	void wizard( PrintWriter Out )
	{
		Document doc;

		if ( XMap != null && XMap.equals( "addamap" )) 
		{
			selectXMap( Out );
			return;
		}
		if ( XDocName == null ) 
		{
			selectXDoc( Out );
			return;
		}
		try {
			DOMParser parser = new DOMParser();
			parser.parse(XDocRoot + XDocName + ".xml" );
			doc = parser.getDocument();
			doc.getDocumentElement().normalize();
			org.w3c.dom.NodeList nodeList = doc.getElementsByTagName( XItem );
			if ( XPTag == null || XData == null )
			{
				if ( XPTag == null ) 
				{
					selectXPTag( nodeList, Out );
				}
				else if ( XData == null )
				{
					selectXData( nodeList, Out );
				}
			}
			else if ( XData.equals( "@" )) // only one item and our stylesheet knows it
			{
				applyXslToDom( addMyNodes( nodeList.item(0) ), Out ); 
			}
			else
			{
				editForm( nodeList, Out );
			}
		} 
		catch (SAXParseException spe) 
		{
			Out.println("\n--Parse error" + ", line " + spe.getLineNumber () + ", uri " + spe.getSystemId ());
			Out.println("   " + spe.getMessage() );
			Exception  x = spe;
			if (spe.getException() != null)
				 x = spe.getException();
			x.printStackTrace();
			return;
		} 
		catch (SAXException sxe) 
		{
			Exception  x = sxe;
			if (sxe.getException() != null)
				x = sxe.getException();
			x.printStackTrace();
			return;
		} 
		catch (IOException ioe) 
		{
		   ioe.printStackTrace();
		   return;
		}
	} // eo buildForm
	
/*
 * Setup our basic page and call the wizard
 */
	public void buildPage (HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
	{
		PrintWriter Out = response.getWriter();
		getReqParams( request ); 
		response.setContentType("text/html");
		wizard( Out );
		Out.close();
	} // eo buildPage

/*
 * answer Get and build a page
 */
	public void doGet (HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
	{
		buildPage( request, response );
	} // eo doGet

/*
 * answer Post and build a page
 */
	public void doPost (HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
	{
		buildPage( request, response );
	} // eo doPost

} // eoclass
