package misc;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class XML {

    // ========================================
    /** une idee de Kohsuke Kawaguchi
				http://weblogs.java.net/blog/kohsuke/archive/2005/07/socket_xml_pitf.html */
    public static class NoWaittingNoCloseInputStream
				extends java.io.FilterInputStream {
				public NoWaittingNoCloseInputStream (InputStream in) { super (in); }

				public int read (byte[] b, int off, int len) throws IOException {
						if (super.available () <= 0)
								return -1;
						int nb = super.read (b, off, len);
						return nb;
				}
				public void close () throws IOException {}
    }

    // ========================================
    public static Document readDocument (InputStream stream)
				throws java.io.IOException {
				try {
						DocumentBuilder documentBuilder =
								DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
						Document document =
								documentBuilder.parse (new NoWaittingNoCloseInputStream (stream));
						document.normalizeDocument ();
						return document;
				} catch (javax.xml.parsers.ParserConfigurationException e) {
						throw new IOException (e);
				} catch (org.xml.sax.SAXException e) {
						throw new IOException (e);
				}
    }

    // ========================================
    public static void writeDocument (Document document, OutputStream stream) {
				try {
            Source source = new DOMSource (document);
            Result result = new StreamResult (stream);
						Transformer xformer =
								TransformerFactory.newInstance ().newTransformer ();
						xformer.setOutputProperty (OutputKeys.INDENT, "yes");
						xformer.setOutputProperty
								("{http://xml.apache.org/xslt}indent-amount", "2");
            xformer.transform (source, result);
						stream.write ("\n".getBytes ());
						stream.flush ();
        } catch (Exception e) {
						Log.keepLastException ("XML::writeDocument", e);
				}
    }

    // ========================================
    public static void writeElement (Element element, OutputStream stream) {
				try {
						DocumentBuilder documentBuilder =
								DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
						Document document = documentBuilder.newDocument ();
						document.setXmlStandalone (true);
						document.appendChild (document.importNode (element, true));
						XML.writeDocument (document, stream);
						stream.flush ();
				} catch (Exception e) {
						Log.keepLastException ("XML::writeElement", e);
				}
    }

    // ========================================
    public final static void putToken (Hashtable<String, String> hashtable,
																			 String token, String value) {
				hashtable.put (token, (value == null) ? "" : value);
    }

    // ========================================
    public final static Hashtable<String, String> node2hashtable (Node child) {
				Hashtable<String, String> hashtable = new Hashtable<String, String> ();
				for (; child != null; child = child.getNextSibling ()) {
						if (child.getNodeType () == Node.ELEMENT_NODE) {
								Element elementTag = (Element) child;
								String token = child.getNodeName ();
								NodeList nodeList = ((Element) child).getChildNodes ();
								if (nodeList.getLength () > 0)
										hashtable.put (token,
																	 ((Text) nodeList.item (0)).getWholeText ());
						}
				}
				return hashtable;
    }

    // ========================================
    public final static void hashtable2node (Document document, Element container,
																						 Hashtable<String, String> hashtable) {
				for (String token : hashtable.keySet ()) {
						Element tag = document.createElement (token);
						tag.appendChild (document.createTextNode (hashtable.get (token)));
						container.appendChild (tag);
				}
    }

    // ========================================
}
