package net.ihe.xcpd.resp.action;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.Serializable;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import net.ihe.gazelle.simulator.common.model.ApplicationConfiguration;
import net.ihe.xcpd.resp.tools.XmlFormatter;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;

/**
 * @author Abderrazek Boufahja > INRIA Rennes IHE development Project
 *
 */
@Stateful
@Name("responderManager")
@Scope(ScopeType.SESSION)
public class ResponderManager implements ResponderManagerLocal, Serializable{

   
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
  //~ Statics variables and Class initializer ////////////////////////////////////////

    /** Logger */
    @Logger
    private static Log log;

    //~ Attribute ///////////////////////////////////////////////////////////////////////
    
    private String requestV3;
    
    private String requestV2;
    
    private String responseV2;
    
    private String responseV3;
    
    private boolean validRequest = false;
    
    private String xmlMetaDataReq = "IHE - XCPD ITI-55 (request)";
    
    private String resultValidation;
    
    //~ getters and setters /////////////////////////////////////////////////////////////
     
    public void setResultValidation(String resultValidation) {
        this.resultValidation = resultValidation;
    }

    public String getResultValidation() {
        return resultValidation;
    }

    public void setXmlMetaDataReq(String xmlMetaDataReq) {
        this.xmlMetaDataReq = xmlMetaDataReq;
    }

    public String getXmlMetaDataReq() {
        return xmlMetaDataReq;
    }

    public void setValidRequest(boolean validRequest) {
        this.validRequest = validRequest;
    }

    public boolean isValidRequest() {
        return validRequest;
    }

    public String getRequestV2() {
        return requestV2;
    }

    public void setRequestV2(String requestV2) {
        this.requestV2 = requestV2;
    }
    
    public String getRequestV3() {
        return requestV3;
    }

    public void setRequestV3(String requestV3) {
        this.requestV3 = requestV3;
    }

    public String getResponseV3() {
        return responseV3;
    }

    public void setResponseV3(String responseV3) {
        this.responseV3 = responseV3;
    }

    public void setResponseV2(String responseV2) {
        this.responseV2 = responseV2;
    }

    public String getResponseV2() {
        return responseV2;
    }

    public static void setLog(Log log) {
        ResponderManager.log = log;
    }

    public static Log getLog() {
        return log;
    }

    // methods /////////////////////////////////////////////////////////////////////////
    
    public void generateResponse() throws Exception{
        if (this.requestV3 != null){
            this.responseV3 = XCPDResponder.getResponseOfRequest(this.requestV3);
            responseV3 = XmlFormatter.transformXMLToHTML(responseV3);
        }
    }
    
    public void validateV3Request(){
        this.validRequest = HL7V3Validator.validateRequestV3(this.requestV3);
        if (this.validRequest){
            FacesMessages.instance().add("Well formed request");
        }
        else{
            FacesMessages.instance().add("Not Well formet request");
        }
    }
    
    public void externalValidation(){
        if (this.xmlMetaDataReq != null){
            this.resultValidation = HL7V3Validator.getValidationResultV3(this.xmlMetaDataReq, requestV3);
        }
        else{
            FacesMessages.instance().add("Chose a type of validation.");
        }
    }
    
    public String getXsdValidationResults()
    {
        if (this.resultValidation != null){
            return resultTransformation(this.resultValidation, "HL7v3Result_xsdValidationPart.xsl");
        }
        return null;
    }
    
    public String getCounters()
    {
        if (this.resultValidation != null){
            return resultTransformation(this.resultValidation, "counters.xsl");
        }
        return null;
    }
    
    public String getDetailedResults()
    {
        if (this.resultValidation != null){
            return resultTransformation(this.resultValidation, "detailedResults.xsl");
        }
        return null;
    }
    
    private static String resultTransformation(String inDetailedResult, String inXslPath)
    {
        if (inDetailedResult == null ||inDetailedResult.length() == 0)
            return null;
        
        if (inXslPath == null || inXslPath.length() == 0)
            return null;
        
        try {
            TransformerFactory tFactory = TransformerFactory.newInstance();

            Transformer transformer = tFactory.newTransformer(
                    new javax.xml.transform.stream.StreamSource(ApplicationConfiguration.getValueOfVariable("gazelle_bin")+ 
                    File.separatorChar + "xsl" +  File.separatorChar + inXslPath));
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            StreamResult out = new StreamResult(baos);
            ByteArrayInputStream bais = new ByteArrayInputStream(inDetailedResult.getBytes());
            transformer.transform(new javax.xml.transform.stream.StreamSource(bais), out);
            String tmp = new String (baos.toByteArray()) ;
            //log.info("trans = " + tmp);
            return tmp;
        } catch (Exception e) {
            e.printStackTrace( );
            return "The document cannot be displayed using this stylesheet";
        }
    }

    // destroy method ///////////////////////////////////////////////////////////////////
    
    @Destroy
    @Remove
    public void destroy()
    {
        log.info("destroy");
    }
}
