/**
 * This servlet is responsible for processing the FormID HTML form into an XML Document.  An XSLT Stylesheet will be applied to the XML
 * Document to convert it to an FOP Document.  The FOP document will be passed to a FOP processor for conversion to PDF.  The PDF file
 * will be emailed to the specified recipient.
 */

package com.equitytg.webTools;

//SDK Packages
import java.io.*;

// Optional Java packages
import javax.mail.internet.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;

// XML Libraries
import org.apache.xerces.dom.*;
import org.apache.xml.serialize.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;

//import javax.xml.transform.stream.`


//FOP Libraries
import org.apache.fop.apps.*;
import org.apache.fop.messaging.MessageHandler;


public class FormIDServlet extends HttpServlet
{
    private static String XSLTPath;
    private DocumentBuilder docBuilder;

    static
    {
        MessageHandler.setOutputMethod( MessageHandler.NONE );
    }

    public void init( ServletConfig config ) throws ServletException
    {
        XSLTPath = config.getInitParameter( "XSLTPath" );

        if( null == XSLTPath )
            throw new ServletException( new String( "Path not found.  No XSLT document available.  Please check your configuration" ) );

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        docFactory.setNamespaceAware( true );
        docFactory.setValidating( false );
        try
        {
            docBuilder = docFactory.newDocumentBuilder();
        }
        catch( ParserConfigurationException pce ){ throw new ServletException( "Parser configuration failure.  Check classpath", pce ); }
    }

    public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
    {
        Document xmlDoc = docBuilder.newDocument();
        Element rootNode = xmlDoc.createElement( "form-id" );
        xmlDoc.appendChild( rootNode );

        doPart1( xmlDoc, rootNode, request );
        doPart2( xmlDoc, rootNode, request );
        rootNode.appendChild( xmlDoc.createElement( "part-three" ) );
        doPart4( xmlDoc, rootNode, request );

        testMethod( response, doPDF( doTransform( xmlDoc ) ) );
   //     testMethod( xmlDoc, response );

    }

    private void doPart1( Document xmlDoc, Element rootNode, HttpServletRequest request )
    {
        Element dateElement = xmlDoc.createElement( "date" );
        Element cikElement = xmlDoc.createElement( "cik" );
        Element requestElement = xmlDoc.createElement( "request" );


        dateElement.appendChild( xmlDoc.createTextNode( request.getParameter( "dateOfApply" ) ) );

        String cik = request.getParameter( "cikNum" );
        if( cik.equals( "" ) ) cikElement.appendChild( xmlDoc.createTextNode( "N/A" ) );
        else cikElement.appendChild( xmlDoc.createTextNode( cik ) );

        String requestTypeS = request.getParameterValues( "appType" )[ 0 ];
        requestElement.setAttribute( "type",requestTypeS );

        Element sec1Element = xmlDoc.createElement( "section-one" );
        Element sec2Element = xmlDoc.createElement( "section-two" );

        sec1Element.appendChild( xmlDoc.createTextNode( request.getParameter( "nameOne" ) ) );
        sec2Element.appendChild( xmlDoc.createTextNode( request.getParameter( "formerName" ) ) );

        Element street = xmlDoc.createElement( "street" );
        Element city = xmlDoc.createElement( "city" );
        Element state = xmlDoc.createElement( "state" );
        Element zip = xmlDoc.createElement( "zip" );
        Element email = xmlDoc.createElement( "email" );

        street.appendChild( xmlDoc.createTextNode( request.getParameter( "address1" ) ) );
        city.appendChild( xmlDoc.createTextNode( request.getParameter( "city1" ) ) );
        state.appendChild( xmlDoc.createTextNode( request.getParameter( "state1" ) ) );
        zip.appendChild( xmlDoc.createTextNode( request.getParameter( "zip1" ) ) );
        email.appendChild( xmlDoc.createTextNode( request.getParameter( "email1" ) ) );

        Element sec3Element = xmlDoc.createElement( "section-three" );
        sec3Element.appendChild( street );
        sec3Element.appendChild( city );
        sec3Element.appendChild( state );
        sec3Element.appendChild( zip );
        sec3Element.appendChild( email );


        Element partOneElement = xmlDoc.createElement( "part-one" );
        partOneElement.appendChild( sec1Element );
        partOneElement.appendChild( sec2Element );
        partOneElement.appendChild( sec3Element );


        if( requestTypeS.equals( "1" ) )
        {
            Element anyElement = xmlDoc.createElement( "section-five" );
            anyElement.appendChild( xmlDoc.createTextNode( "true" ) );
            partOneElement.appendChild( anyElement );
        }
        else
        {
            String tmp[] = request.getParameterValues( "amendedApp" );

            if( null != tmp )
            {
                Element e = xmlDoc.createElement( "section-six" );
                e.setAttribute( "checked", "true" );
                tmp = request.getParameterValues( "ammendedAppValues" );

                for( int i = 0; i < tmp.length; i++ )
                {
                    if( tmp[ i ].equals( "ccc" ) )
                    {
                        Element element = xmlDoc.createElement( "ccc" );
                        element.setAttribute( "checked", "true" );
                        e.appendChild( element );
                    }
                    else if( tmp[ i ].equals( "password" ) )
                    {
                        Element element = xmlDoc.createElement( "password" );
                        element.setAttribute( "checked", "true" );
                        e.appendChild( element );
                    }
                    else if( tmp[ i ].equals( "pmac" ) )
                    {
                        Element element = xmlDoc.createElement( "pmac" );
                        element.setAttribute( "checked", "true" );
                        e.appendChild( element );
                    }
                }
                partOneElement.appendChild( e );
            }
            else
            {
                Element anyElement = xmlDoc.createElement( "section-seven" );
                anyElement.setAttribute( "checked", "true" );
                partOneElement.appendChild( anyElement );
            }
        }
        rootNode.appendChild( dateElement );
        rootNode.appendChild( cikElement );
        rootNode.appendChild( requestElement );
        rootNode.appendChild( partOneElement );
    }

    private void doPart2( Document xmlDoc, Element rootNode, HttpServletRequest request )
    {
        Element partTwoElement = xmlDoc.createElement( "part-two" );

        if( null != request.getParameterValues( "currentFileSec" ) )
        {
            Element sectionOne = xmlDoc.createElement( "section-one" );
            sectionOne.setAttribute( "checked", "true" );

            String tmp = request.getParameter( "_1933_2_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "2" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1933_33_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "33" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1933_333_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "333" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1934_0_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "0" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1934_1_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "1" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1934_28_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "28" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1935_70_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "70" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1935_69_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "69" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1940_811_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "811" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "_1940_814_" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "814" );
                e.appendChild( xmlDoc.createTextNode( tmp ) );
                sectionOne.appendChild( e );
            }

            tmp = request.getParameter( "other_pre" );
            if( !tmp.equals( "" ) )
            {
                Element e = xmlDoc.createElement( "file-number" );
                e.setAttribute( "prefix", "other" );
                e.appendChild( xmlDoc.createTextNode(  tmp + '-' + request.getParameter("other_2" ) ) );
                sectionOne.appendChild( e );
            }
            partTwoElement.appendChild( sectionOne );
        }

        Element ref = xmlDoc.createElement( "ein" );
        ref.appendChild( xmlDoc.createTextNode( request.getParameter( "fin1" ) + '-' + request.getParameter( "fin2" ) ) );

        Element sec2Element = xmlDoc.createElement( "section-two" );
        sec2Element.appendChild( ref );

        ref = xmlDoc.createElement( "phone" );
        ref.appendChild( xmlDoc.createTextNode(
            '(' + request.getParameter( "areaCodeII" ) +  ')' + ' ' + request.getParameter( "preII" ) + '-' + request.getParameter( "postII" ) ) );
        sec2Element.appendChild( ref );

        partTwoElement.appendChild( sec2Element );

        String placeHolder = request.getParameter( "bizAddress" );

        if( !placeHolder.equals( "" ) )
        {
            ref = xmlDoc.createElement( "street" );
            ref.appendChild( xmlDoc.createTextNode( placeHolder ) ) ;

            Element sec3Element = xmlDoc.createElement( "section-three" );
            sec3Element.appendChild( ref );

            ref = xmlDoc.createElement( "city" );
            ref.appendChild( xmlDoc.createTextNode( request.getParameter( "bizCity" ) ) );
            sec3Element.appendChild( ref );

            ref = xmlDoc.createElement( "state" );
            ref.appendChild( xmlDoc.createTextNode( request.getParameter( "bizState" ) ) );
            sec3Element.appendChild( ref );

            ref = xmlDoc.createElement( "zip" );
            ref.appendChild( xmlDoc.createTextNode( request.getParameter( "bizZip" ) ) );
            sec3Element.appendChild( ref );

            partTwoElement.appendChild( sec3Element );
        }

        ref = xmlDoc.createElement( "soi" );
        ref.appendChild( xmlDoc.createTextNode( request.getParameter( "soi" ) ) );

        Element sec4Element = xmlDoc.createElement( "section-four" );
        sec4Element.appendChild( ref );

        ref = xmlDoc.createElement( "fiscal-year-end" );
        ref.appendChild( xmlDoc.createTextNode( request.getParameter( "fiscalYearEndMonth" ) + '/' + request.getParameter( "fiscalYearEndDay" ) ) ) ;
        sec4Element.appendChild( ref );

        partTwoElement.appendChild( sec4Element );

        rootNode.appendChild( partTwoElement );
    }

    private void doPart4( Document xmlDoc, Element rootNode, HttpServletRequest request )
    {
        Element section = xmlDoc.createElement( "section-one" );
        section.appendChild( xmlDoc.createTextNode( request.getParameter( "personReceiveSec" ) ) );

        Element partFourElement = xmlDoc.createElement( "part-four" );
        partFourElement.appendChild( section );

        section = xmlDoc.createElement( "section-two" );
        section.appendChild( xmlDoc.createTextNode( '(' + request.getParameter( "areaCodeIV" ) + ')' + ' ' + request.getParameter( "preIV" ) +
            '-' + request.getParameter( "postIV" ) ) );
        partFourElement.appendChild( section );

        String temp = request.getParameter( "address4" );
        if( !temp.equals( "" ) )
        {
            section = xmlDoc.createElement( "section-three" );
            Element e = xmlDoc.createElement( "street" );
            e.appendChild( xmlDoc.createTextNode( temp ) );
            section.appendChild( e );

            e = xmlDoc.createElement( "city" );
            e.appendChild( xmlDoc.createTextNode( request.getParameter( "city4" ) ) );
            section.appendChild( e );

            e = xmlDoc.createElement( "state" );
            e.appendChild( xmlDoc.createTextNode( request.getParameter( "state4" ) ) );
            section.appendChild( e );

            e = xmlDoc.createElement( "zip" );
            e.appendChild( xmlDoc.createTextNode( request.getParameter( "zip4" ) ) );
            section.appendChild( e );

            partFourElement.appendChild( section );
        }

    }

    /**
     * Do an XML + XSL -> XSL:FO Transformation
     */
    private Document doTransform( Document xmlSource ) throws ServletException, IOException
    {
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Document foDoc = new org.apache.xerces.dom.DocumentImpl();
        try
        {
            Transformer transformer = tFactory.newTransformer( new javax.xml.transform.stream.StreamSource( new BufferedInputStream( new FileInputStream( this.XSLTPath ) ) ) );
            transformer.transform( new DOMSource( xmlSource ), new DOMResult( foDoc ) );
        }
        catch( TransformerException tre ){ throw new ServletException( "XSL Transformation Failed", tre ); }

        return foDoc;
    }

    /**
     * Transform the XSL:FO document to a PDF document
     *
     * @return  A byte array representing the PDF document
     */
    private byte[] doPDF( Document doc ) throws ServletException, IOException
    {
        Driver fopDriver = new Driver();
        fopDriver.setRenderer( "org.apache.fop.render.pdf.PDFRenderer", Version.getVersion() );
        fopDriver.addElementMapping( "org.apache.fop.fo.StandardElementMapping" );
        fopDriver.addElementMapping( "org.apache.fop.svg.SVGElementMapping" );
        fopDriver.addPropertyList( "org.apache.fop.fo.StandardPropertyListMapping" );
        fopDriver.addPropertyList( "org.apache.fop.svg.SVGPropertyListMapping" );

        ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();

        try
        {
            fopDriver.setOutputStream( pdfStream );
            fopDriver.buildFOTree( doc );
            fopDriver.format();
            fopDriver.render();
            pdfStream.flush();
            pdfStream.close();
        }
        catch( FOPException fopx ){ throw new ServletException( "FOP Transformation failed", fopx ); }

        return pdfStream.toByteArray();
    }

    private void testMethod( Document doc, HttpServletResponse response ) throws IOException
    {
        XMLSerializer xmlSerializer = new XMLSerializer();

        response.setContentType( "text/xml" );
        xmlSerializer.setOutputByteStream( response.getOutputStream() );

        xmlSerializer.serialize( doc );
    }

    private void testMethod( HttpServletResponse response, byte[] bytes ) throws IOException
    {
        response.setContentType( "application/pdf" );
        ServletOutputStream oStream = response.getOutputStream();
        response.setHeader( "Vary", "Accept-Encoding" );
        oStream.write( bytes );
        oStream.flush();
        oStream.close();
    }

    public static void main( String[] args ) throws Exception
    {
        FormIDServlet servlet = new FormIDServlet();
        org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser();
        parser.parse( new InputSource( new BufferedInputStream( new FileInputStream( "D:\\programming\\XML\\formID\\formID_instance.xml" ) ) ) );

        byte[] pdf = servlet.doPDF( servlet.doTransform( parser.getDocument() ) );

        BufferedOutputStream oStream = new BufferedOutputStream( new FileOutputStream( "d:\\temp\\servlet.pdf" ) );

        oStream.write( pdf );
        oStream.flush();
        oStream.close();
    }
}