/*
 * NIST
 * AnalyzeResults.java Jun 18, 2008
 *
 * This code was produced by the National Institute of Standards and
 * Technology (NIST). See the "nist.disclaimer" file given in the distribution
 * for information on the use and redistribution of this software.
 */

package gov.nist.hl7.testengine.analyzeresults;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.rmi.RemoteException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import gov.nist.hl7.testengine.main.Utils;
import gov.nist.hl7.testframework.BegoniaDatabase;
import gov.nist.hl7.testframework.MirthMessage;
import gov.nist.hl7.ws.messagevalidation.Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub;
import gov.nist.hl7.ws.messagevalidation.SetValidationContextFaultException;
import gov.nist.hl7.ws.messagevalidation.Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub.LoadResource;
import gov.nist.hl7.ws.messagevalidation.Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub.LoadMessage;
import gov.nist.hl7.ws.messagevalidation.Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub.LoadProfile;
import gov.nist.hl7.ws.messagevalidation.Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub.SetValidationContext;

import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;


public class AnalyzeResults {

    protected String xslPATH;
    protected Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub mvStub;

    public AnalyzeResults(String url, String xslpath) throws AxisFault {
        xslPATH = xslpath;
        // Create the client instance
        mvStub = new Hl7MessageValidationHl7MessageValidationSOAP12Port_httpStub(url + "Hl7MessageValidation");
        // Set the timeout for 60 minutes (for large files)
        Options options = mvStub._getServiceClient().getOptions();
        options.setTimeOutInMilliSeconds(600000);
    }

    /**
     * @param args
     * @throws SQLException
     * @throws SetValidationContextFaultException
     * @throws IOException
     * @throws TransformerException
     * @throws TransformerFactoryConfigurationError
     */
    public String validate() throws SQLException, SetValidationContextFaultException, IOException, TransformerFactoryConfigurationError, TransformerException {

        // Get all the messages from Begonia
        //ArrayList<MirthMessageExtend> messages = getLocalDB();
        ArrayList<MirthMessageExtend> messages = getBegoniaDB();

        // Validate the messages
        Iterator<MirthMessageExtend> itMessages = messages.iterator();
        while (itMessages.hasNext()) {
            MirthMessageExtend message = itMessages.next();
            FileWriter f = new FileWriter("files/messages/" + message.getName() + ".er7");
            f.write(message.getMessage());
            f.close();

            String report = validateMessage(message);
            f = new FileWriter("files/reports/xml/" + message.getName() + ".xml");
            f.write(report);
            f.close();

            // transform the report into an HTML document
            copyHTML(report, "files/reports/html/" + message.getName() + ".html");
        }

        return "true";
    }

    /**
     *
     * @param report
     * @param dest
     * @throws TransformerFactoryConfigurationError
     * @throws TransformerException
     * @throws IOException
     */
    private void copyHTML(String report, String dest) throws TransformerFactoryConfigurationError, TransformerException, IOException {
        File fStyleSheet = new File(xslPATH);
        Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(fStyleSheet));

        StreamSource source = new StreamSource(new StringReader(report));
        ByteArrayOutputStream resultStream = new ByteArrayOutputStream();

        StreamResult result = new StreamResult(resultStream);

        transformer.transform(source, result);

        FileWriter fw = new FileWriter(dest);
        fw.write(resultStream.toString());
        fw.close();
    }

    /**
     *
     * @param message
     * @return
     * @throws RemoteException
     * @throws SetValidationContextFaultException
     */
    private String validateMessage(MirthMessageExtend message) throws RemoteException,
    SetValidationContextFaultException {

        String sendingApp = message.getSendingApplication();
        String profile = "", mvc = "", table = "";
        // Set up the references to the profiles, MVCs, tables

        if ("ACK".equals(message.getMsgCode())) {
            profile = Utils.getContents(new File("files/profiles/ACK_A04.xml"));
        } else {
            if ("NIST Pearl PIX Source".equals(sendingApp)) {
                profile = Utils.getContents(new File("files/profiles/pixSourceM/ADT_A04.xml"));
                mvc = Utils.getContents(new File("files/validationcontexts/PixSourceMValidationContext.xml"));
            } else if ("NIST Flame PIX Source".equals(sendingApp)) {
                profile = Utils.getContents(new File("files/profiles/pixSourceL/ADT_A04.xml"));
                mvc = Utils.getContents(new File("files/validationcontexts/PixSourceLValidationContext.xml"));
            } else if ("NIST Swan PIX Manager".equals(sendingApp)) {
                profile = Utils.getContents(new File("files/profiles/pixManager/RSP_K23.xml"));
                mvc = Utils.getContents(new File("files/validationcontexts/PixManagerValidationContext.xml"));
            } else if ("NIST Hydra PIX Consumer".equals(sendingApp)) {
                profile = Utils.getContents(new File("files/profiles/pixConsumer/QBP_Q23.xml"));
                mvc = Utils.getContents(new File("files/validationcontexts/PixConsumerValidationContext.xml"));

            }
        }

        if (message.getVersionId().equals("2.5")) {
            table = Utils.getContents(new File("files/tables/PIX_Tables.2.5.xml"));
        } else if (message.getVersionId().equals("2.3.1")) {
            table = Utils.getContents(new File("files/tables/PIX_Tables.2.3.1.xml"));
        }


        // 1. Load the profile
        LoadProfile lp = new LoadProfile();
        lp.setXmlProfile(profile);
        if (!mvStub.loadProfile(lp).get_return()) {
            throw new AxisFault("Error Loading the Profile.");
        }

        // 2. Load the message
        LoadMessage lm = new LoadMessage();
        String messageStr = message.getMessage();
        lm.setMessageStr(messageStr);
        if (!mvStub.loadMessage(lm).get_return()) {
            throw new AxisFault("Error Loading the Message.");
        }

        // 3. Load the MVC
        if (!"".equals(mvc)) {
            SetValidationContext svc = new SetValidationContext();
            svc.setXmlValidationContext(mvc);
            if (!mvStub.setValidationContext(svc).get_return()) {
                throw new AxisFault("Error Loading the MVC.");
            }
        }

        // 4. Load the table
        if (!"".equals(table)) {

            LoadResource lr = new LoadResource();
            lr.setXmlResource(table);
            if (!mvStub.loadResource(lr).get_return()) {
                throw new AxisFault("Error Loading the resource.");
            }
        }

        // 4. Call the Validate Method
        mvStub.validate();
        return mvStub.getValidationReport().get_return();
    }

    /**
     *
     * @return
     * @throws SQLException
     */
    private ArrayList<MirthMessageExtend> getBegoniaDB() throws SQLException {
        ArrayList<MirthMessage> al = BegoniaDatabase.getInstance().getMessages(6);
        ArrayList<MirthMessageExtend> alExtend = new ArrayList<MirthMessageExtend>();

        Iterator<MirthMessage> it = al.iterator();
        while (it.hasNext()) {
            MirthMessage curMsg = it.next();
            MirthMessageExtend newMsg = new MirthMessageExtend();
            newMsg.setMessage(curMsg.getMessage());
            newMsg.setMessageTime(curMsg.getMessageTime());
            newMsg.setMsgCode(curMsg.getMsgCode());
            newMsg.setSendingApplication(curMsg.getSendingApplication());
            newMsg.setTriggerEvent(curMsg.getTriggerEvent());
            newMsg.setVersionId(curMsg.getVersionId());
            newMsg.setName("msg-" + curMsg.getMsgCode() + "_" + curMsg.getTriggerEvent()
                    + "-" + curMsg.getSendingApplication() + "-" + curMsg.getMessageTime());
            alExtend.add(newMsg);
        }

        return alExtend;
    }

    /**
     *
     * @return
     */
    private ArrayList<MirthMessageExtend> getLocalDB() {
        ArrayList<MirthMessageExtend> al = new ArrayList<MirthMessageExtend>();
        MirthMessageExtend mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/1_pixSourceM to pixManager.txt")));
        mm.setName("1_pixSourceM to pixManager");
        mm.setSendingApplication("NIST Pearl PIX Source");
        mm.setMsgCode("ADT");
        mm.setVersionId("2.3.1");
        al.add(mm);

        mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/2_pixManager to pixSourceM.txt")));
        mm.setName("2_pixManager to pixSourceM");
        mm.setSendingApplication("NIST Swan PIX Manager");
        mm.setMsgCode("ACK");
        mm.setVersionId("2.3.1");
        al.add(mm);

        mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/3_pixSourceL to pixManager.txt")));
        mm.setName("3_pixSourceL to pixManager");
        mm.setSendingApplication("NIST Flame PIX Source");
        mm.setMsgCode("ADT");
        mm.setVersionId("2.3.1");
        al.add(mm);

        mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/4_pixManager to pixSourceL.txt")));
        mm.setName("4_pixManager to pixSourceL");
        mm.setSendingApplication("NIST Swan PIX Manager");
        mm.setMsgCode("ACK");
        mm.setVersionId("2.3.1");
        al.add(mm);

        mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/5_pixConsumer to pixManager.txt")));
        mm.setName("5_pixConsumer to pixManager");
        mm.setSendingApplication("NIST Hydra PIX Consumer");
        mm.setMsgCode("QBP");
        mm.setVersionId("2.5");
        al.add(mm);

        mm = new MirthMessageExtend();
        mm.setMessage(Utils.getContents(new File("files/messages/6_pixManager to pixConsumer.txt")));
        mm.setName("6_pixManager to pixConsumer");
        mm.setSendingApplication("NIST Swan PIX Manager");
        mm.setMsgCode("RSP");
        mm.setVersionId("2.5");
        al.add(mm);
        return al;
    }
}
