package com.iverticalleap.util.xml;

import org.w3c.dom.Node;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 *  Useful operations to aid in the use of the TRaX API
 *
 * @author     Kevin Ross
 * @version $Revision: 1.3 $ $Date: 2002/05/03 18:11:44 $
 */
public class TraxUtility {

    private TraxUtility() { }


    /**
     *@param  xslSource
     *@param  uriResolver
     *@return Transformer with a default configuration.
     *@exception  TransformerConfigurationException
     */
    public static Transformer getTransformer( Source xslSource, URIResolver uriResolver )
        throws TransformerConfigurationException {

        if ( xslSource == null ) {
            throw new IllegalArgumentException( "xslSource cannot be null." );
        }

        System.out.println( "xslSource systemId: " + xslSource.getSystemId() );
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        javax.xml.transform.Templates stylesheetTemplates = transformerFactory.newTemplates( xslSource );

        if ( null == stylesheetTemplates ) {

            throw new NullPointerException( "Unable to get stylesheet from xslSource: " + xslSource );
        }

        //
        // Get the transformer based on this template
        //
        Transformer transformer = stylesheetTemplates.newTransformer();
        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );

        if ( uriResolver != null ) {
            transformer.setURIResolver( uriResolver );
        }

        return transformer;
    }


    /**
     *  Gets the Transformer property of the TraxUtility class
     *
     *@param  xslSource
     *@return                                        Transformer -
     *@exception  TransformerConfigurationException
     */
    public static Transformer getTransformer( Source xslSource )
        throws TransformerConfigurationException {

        return getTransformer( xslSource, ( URIResolver ) null );
    }


    /**
     *  Gets the Transformer property of the TraxUtility class
     *
     *@param  uriResolver
     *@return                                        Transformer -
     *@exception  TransformerConfigurationException
     */
    public static Transformer getTransformer( URIResolver uriResolver )
        throws TransformerConfigurationException {

        TransformerFactory transformerFactory = TransformerFactory.newInstance();

        if ( uriResolver != null ) {
            transformerFactory.setURIResolver( uriResolver );
        }

        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
        return transformer;
    }


    /**
     *  Gets the Transformer property of the TraxUtility class
     *
     *@return                                        Transformer -
     *@exception  TransformerConfigurationException
     */
    public static Transformer getTransformer()
        throws TransformerConfigurationException {

        return getTransformer( ( URIResolver ) null );
    }


    /**
     *  Gets the XMLString property of the TraxUtility class
     *
     *@param  xmlContent
     *@return                              XMLString -
     *@exception  TransformationException
     */
    public static String getXMLString( String xmlContent )
        throws TransformationException {

        return getXMLString( getSource( xmlContent ) );
    }


    /**
     *  Gets the XMLString property of the TraxUtility class
     *
     *@param  node
     *@return                              XMLString -
     *@exception  TransformationException
     */
    public static String getXMLString( Node node )
        throws TransformationException {

        try {

            return getXMLString( new DOMSource( node ) );
        }
        catch ( Exception e ) {
            throw new TransformationException( TraxUtility.class, "getXMLString()", e );
        }
    }


    /**
     *  Gets the XMLString property of the TraxUtility class
     *
     *@param  source
     *@return                              XMLString -
     *@exception  TransformationException
     */
    public static String getXMLString( Source source )
        throws TransformationException {

        try {
            StringWriter stringWriter = new StringWriter();
            getTransformer().transform( source, new StreamResult( stringWriter ) );
            return stringWriter.toString();
        }
        catch ( Exception e ) {
            throw new TransformationException( TraxUtility.class, "getXMLString()", e );
        }
    }


    /**
     *  Gets the Node property of the TraxUtility class
     *
     *@param  source
     *@return                              Node -
     *@exception  TransformationException
     */
    public static Node getNode( Source source )
        throws TransformationException {

        try {
            DOMResult domResult = new DOMResult();
            getTransformer().transform( source, domResult );
            return domResult.getNode();
        }
        catch ( Exception e ) {
            throw new TransformationException( TraxUtility.class, "getNode()", e );
        }
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  reader
     *@return         Source -
     */
    public static Source getSource( java.io.Reader reader ) {

        if ( reader == null ) {

            throw new IllegalArgumentException( "reader cannot be null." );
        }

        return new StreamSource( reader );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  content
     *@return          Source -
     */
    public static Source getSource( Content content ) {

        if ( content == null ) {

            throw new IllegalArgumentException( "content cannot be null." );
        }

        return getSource( content.getNode() );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  node
     *@return       Source -
     */
    public static Source getSource( Node node ) {

        if ( node == null ) {

            throw new IllegalArgumentException( "node cannot be null." );
        }

        return new DOMSource( node );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  inputSource
     *@return              Source -
     */
    public static Source getSource( org.xml.sax.InputSource inputSource ) {

        if ( inputSource == null ) {

            throw new IllegalArgumentException( "inputSource cannot be null." );
        }

        return new javax.xml.transform.sax.SAXSource( inputSource );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  inputStream
     *@return              Source -
     */
    public static Source getSource( InputStream inputStream ) {

        if ( inputStream == null ) {

            throw new IllegalArgumentException( "inputStream cannot be null." );
        }

        return new StreamSource( inputStream );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  xmlContent
     *@return             Source -
     */
    public static Source getSource( String xmlContent ) {

        if ( xmlContent == null ) {

            throw new IllegalArgumentException( "xmlContent cannot be null." );
        }

        return new StreamSource( new java.io.StringReader( xmlContent ) );
    }


    /**
     *  Gets the Source property of the TraxUtility class
     *
     *@param  url
     *@return      Source -
     */
    public static Source getSource( URL url ) {
        /*
         *  throws MalformedURLException, IOException
         */

        if ( url == null ) {

            throw new IllegalArgumentException( "url cannot be null." );
        }

        return new StreamSource( url.toExternalForm() );
    }


    /**
     *  Gets the Result property of the TraxUtility class
     *
     *@param  writer
     *@return         Result -
     */
    public static javax.xml.transform.Result getResult( java.io.Writer writer ) {

        if ( writer == null ) {

            throw new IllegalArgumentException( "writer cannot be null." );
        }

        return new StreamResult( writer );
    }


    /**
     *@param  xmlContentInputStream
     *@param  xsltInputStream
     *@return
     *@exception  TransformationException
     */
    public static String transform( InputStream xmlContentInputStream, InputStream xsltInputStream )
        throws TransformationException {

        URIResolver uriResolver = null;

        // Get the XML input document and the stylesheet.
        Source xmlSource = getSource( xmlContentInputStream );
        Source xslSource = getSource( xsltInputStream );

        return transform( xmlSource, xslSource, uriResolver );
    }


    /**
     *@param  xmlContent
     *@param  xsltURL
     *@return
     *@exception  TransformationException
     */
    public static String transform( String xmlContent, URL xsltURL )
        throws TransformationException {

        return transform( getSource( xmlContent ), getSource( xsltURL ) );
    }


    /**
     *@param  node
     *@param  xsltURL
     *@return
     *@exception  TransformationException
     */
    public static String transform( Node node, URL xsltURL )
        throws TransformationException {

        URIResolver uriResolver = null;

        // Get the XML input document and the stylesheet.
        Source xmlSource = getSource( node );
        Source xslSource = getSource( xsltURL );

        return transform( xmlSource, xslSource, uriResolver );
    }


    /**
     *@param  xmlSource
     *@param  xslSource
     *@return
     *@exception  TransformationException
     */
    public static String transform( Source xmlSource, Source xslSource )
        throws TransformationException {

        URIResolver uriResolver = null;
        return transform( xmlSource, xslSource, uriResolver );
    }


    /**
     *@param  xmlSource
     *@param  xslSource
     *@param  uriResolver
     *@return
     *@exception  TransformationException
     */
    public static String transform( Source xmlSource, Source xslSource, URIResolver uriResolver )
        throws TransformationException {

        try {

            return transform( xmlSource, getTransformer( xslSource, uriResolver ) );
        }
        catch ( TransformerConfigurationException e ) {

            throw new TransformationException( TraxUtility.class, "transformAsNode", e );
        }
    }


    /**
     *@param  xmlSource
     *@param  transformer
     *@return
     *@exception  TransformationException
     */
    public static String transform( Source xmlSource, Transformer transformer )
        throws TransformationException {

        if ( xmlSource == null ) {
            throw new IllegalArgumentException( "xmlSource cannot be null." );
        }

        if ( transformer == null ) {
            throw new IllegalArgumentException( "transformer cannot be null." );
        }

        try {

            StringWriter stringWriter = new StringWriter();
            StreamResult result = new StreamResult( stringWriter );
            transformer.transform( xmlSource, result );

            return stringWriter.toString();
        }
        catch ( TransformerConfigurationException e ) {

            throw new TransformationException( TraxUtility.class, "transform", "\nInvalid Transformer configuration.", e );
        }
        catch ( TransformerException e ) {

            throw new TransformationException( TraxUtility.class, "transform", "\nTransformation failed.", e );
        }
    }


    /**
     *@param  xmlContent
     *@param  xsltURL
     *@return
     *@exception  TransformationException
     */
    public static Node transformAsNode( String xmlContent, URL xsltURL )
        throws TransformationException {

        URIResolver uriResolver = null;

        // Get the XML input document and the stylesheet.
        Source xmlSource = getSource( xmlContent );
        Source xslSource = getSource( xsltURL );

        return transformAsNode( xmlSource, xslSource, uriResolver );
    }

    /**
     *@param  xmlSource
     *@param  xslSource
     *@return
     *@exception  TransformationException
     */
    public static Node transformAsNode( Source xmlSource, Source xslSource )
        throws TransformationException {

            return transformAsNode( xmlSource, xslSource, null );
    }
    
    /**
     *@param  xmlSource
     *@param  xslSource
     *@param  uriResolver
     *@return
     *@exception  TransformationException
     */
    public static Node transformAsNode( Source xmlSource, Source xslSource, URIResolver uriResolver )
        throws TransformationException {

        try {

            return transformAsNode( xmlSource, getTransformer( xslSource, uriResolver ) );
        }
        catch ( TransformerConfigurationException e ) {

            throw new TransformationException( TraxUtility.class, "transformAsNode", e );
        }
    }


    /**
     *@param  xmlSource
     *@param  transformer
     *@return
     *@exception  TransformationException
     */
    public static Node transformAsNode( Source xmlSource, Transformer transformer )
        throws TransformationException {

        if ( xmlSource == null ) {
            throw new IllegalArgumentException( "xmlSource cannot be null." );
        }

        try {

            DOMResult domResult = new DOMResult();
            transformer.transform( xmlSource, domResult );

            return domResult.getNode();
        }
        catch ( TransformerConfigurationException e ) {

            throw new TransformationException( TraxUtility.class, "transform", "\nInvalid Transformer configuration.", e );
        }
        catch ( TransformerException e ) {

            throw new TransformationException( TraxUtility.class, "transform", "\nTransformation failed.", e );
        }
    }
}
