package scriptbuilder.structures;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Utility methods that build XML elements from content strings.
 * @author Bryan McGuffin
 */
public class XMLBuilder
{

    /**
     * XML-style opening tag. Example: if given string "my_tag", returns
     * "<my_tag>".
     *
     * @param s the XML element to be included in the tag.
     * @return the properly formatted tag
     */
    public static String openTag(String s)
    {
        return "<" + s + ">";
    }

    /**
     * XML-style closing tag. Example: if given string "my_tag", returns
     * "</my_tag>".
     *
     * @param s the XML element to be included in the tag.
     * @return the properly formatted tag
     */
    public static String closeTag(String s)
    {
        return "</" + s + ">\n";
    }

    /**
     * XML-style empty tag. Example: if given string "my_tag", returns
     * "<my_tag/>".
     *
     * @param s the XML element to be included in the tag.
     * @return the properly formatted tag
     */
    public static String emptyTag(String s)
    {
        return "<" + s + "/>\n";
    }

    /**
     * Creates a pair of XML open and close tags to wrap a simple line of data.
     * Useful if only one element need be enclosed in this particular tag.
     *
     * @param s the data to be wrapped
     * @param e the XML element represented by the data
     * @return an XML string of the format <my_tag>some_data_goes_here</my_tag>
     */
    public static String simpleTag(String s, ELEMENT e)
    {
        String output = "";
        if (s == null)
        {
            s = "";
        }

        output += openTag(e.tag);
        output += s;
        output += closeTag(e.tag);

        return output;
    }

    /**
     * @return the xml string with the link to external DTD for XML script files.
     */
    public static String externalDTD()
    {
        return "<!DOCTYPE TMC_SCRIPT SYSTEM \"incident_script.dtd\">\n";
    }
    /**
     * @return The xml string that starts the document.
     */
    public static String xmlHeader()
    {
        return "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
    }
    /**
     * Prettyprint an XML string.
     * @param xmlString (works best if it contains no newlines)
     * @return String that has been nicely formatted with indentation
     */
    public static String prettyPrintXML(String xmlString)
    {
        Document xmlDoc = null;
        String formattedXML = "";
        try {
            xmlDoc = toXmlDocument(xmlString);
            formattedXML = prettyprintdoc(xmlDoc);
        } catch (ParserConfigurationException | SAXException | IOException
                | TransformerException e) {
            e.printStackTrace();
        }
        // Prepend the header and externalDTD lines.  (This must be done after
        // prettyprinting, which tries to read the externalDTD if the link is present.)
        // Fixes #239.
        formattedXML = xmlHeader() + externalDTD() + formattedXML;
        return formattedXML;
    }
    
 
    /**
     * Prettyprint an XML document.
     * @param document an "ugly" XML document
     * @return String nicely formatted XML with indentation
     * @throws TransformerException 
     */
    public static String prettyprintdoc(Document document)
            throws TransformerException {
        TransformerFactory transformerFactory = TransformerFactory
                .newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(
                "{http://xml.apache.org/xslt}indent-amount", "2");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        DOMSource source = new DOMSource(document);
        StringWriter strWriter = new StringWriter();
        StreamResult result = new StreamResult(strWriter);
 
        transformer.transform(source, result);
 
        return strWriter.getBuffer().toString();
 
    }
 
    /** Create an XML Document from a string that is in xml format.
     * 
     * @param str xml format content
     * @return Document containing the specified content.
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException 
     */
    public static Document toXmlDocument(String str)
            throws ParserConfigurationException, SAXException, IOException {
 
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
                .newInstance();
        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
        Document document = docBuilder.parse(new InputSource(new StringReader(
                str)));
 
        return document;
    }
}
