package net.ihe.xcpd.init.action;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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.gazelle.simulator.common.tf.model.Transaction;
import net.ihe.xcpd.init.assertion.AssertionGenerator;
import net.ihe.xcpd.init.model.Responder;
import net.ihe.xcpd.init.model.XCPDMessage;
import net.ihe.xcpd.init.tools.XmlFormatter;
import net.ihe.xcpd.init.transport.Client2Server;
import net.ihe.xcpd.init.transport.SOAPSender2;

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.annotations.Synchronized;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;

/**
 * @author Abderrazek Boufahja > INRIA Rennes IHE development Project
 *
 */
@Stateful
@Synchronized(timeout=100000)
@Name("initRespManager")
@Scope(ScopeType.SESSION)
public class ResponderManager extends AbstractGenerator 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 wsURL;
    
    private String responseV3;
    
    private String soapRequest;
    
    private boolean validRequest = false;
    
    private String xmlMetaDataReq = "IHE - XCPD ITI-55 (request)";
    
    private String resultValidation;
    
    //private String assertionType;
    
    private String completeAssertion;
    
    //private String stsUrl;
    
    private Boolean addAssertion = false;
    
    private boolean useRequestGenerator = false;
    
    private String generatedMessage;
    
   //  getter and setters /////////////////////////////////////////////////////
    
    public void setUseRequestGenerator(boolean useRequestGenerator) {
        this.useRequestGenerator = useRequestGenerator;
    }

    public String getGeneratedMessage() {
        return generatedMessage;
    }

    public void setGeneratedMessage(String generatedMessage) {
        this.generatedMessage = generatedMessage;
    }

    public boolean isUseRequestGenerator() {
        return useRequestGenerator;
    }

    public void setAddAssertion(Boolean addAssertion) {
        this.addAssertion = addAssertion;
    }

    public Boolean getAddAssertion() {
        return addAssertion;
    }

    public void setSoapRequest(String soapRequest) {
        this.soapRequest = soapRequest;
    }

    public String getSoapRequest() {
        return soapRequest;
    }

    public void setCompleteAssertion(String completeAssertion) {
        this.completeAssertion = completeAssertion;
    }

    public String getCompleteAssertion() {
        return completeAssertion;
    }
    
//    public void setAssertionType(String assertionType) {
//        this.assertionType = assertionType;
//    }
//
//    public String getAssertionType() {
//        return assertionType;
//    }

    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() {
        if (this.useRequestGenerator == true){
            validRequest = true;
        }
        return validRequest;
    }

    public void setWsURL(String wsURL) {
        this.wsURL = wsURL;
    }

    public String getWsURL() {
        return wsURL;
    }

    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 static void setLog(Log log) {
        ResponderManager.log = log;
    }

    public static Log getLog() {
        return log;
    }
    
    // methods /////////////////////////////////////////////////////////////////////////
    
    public void generateResponse() throws Exception{
        if (this.useRequestGenerator == true){
            this.requestV3 = this.generateMessageFromValuesForAbstract();
            if (this.requestV3 == null){
                return;
            }
        }
        if ((!this.requestV3.equals(""))&&(!this.wsURL.equals(""))){
            Client2Server c2s = new Client2Server();
            if (this.addAssertion){            	
                String nameID = ApplicationConfiguration.getValueOfVariable("nameID");
                String patientID = ApplicationConfiguration.getValueOfVariable("patientID");
                String assertion = AssertionGenerator.generateToken(nameID, patientID);
                this.soapRequest = c2s.createMessageSoap(assertion, this.requestV3, this.wsURL);
                this.responseV3 = SOAPSender2.sendToUrlAndGetResponse(wsURL, this.soapRequest);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
            }
            else{
                this.responseV3 = HL7V3Responder.generateResponse(this.requestV3, this.wsURL, false);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = c2s.createMessageSoap(null, this.requestV3, this.wsURL);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
            }
            XCPDMessage mess = new XCPDMessage();
            mess.setMessageSentContent(this.soapRequest.getBytes());
            mess.setMessageResponseContent(this.responseV3.getBytes());
            mess.setMessageType("PRPA_IN201305UV02");
            mess.setTimeStamp(new Date());
            mess.setContext(MessageSwitch.GUI);
            mess.setTransaction(Transaction.GetTransactionByKeyword("ITI-55"));
            if (this.wsURL != null){
                Responder res = Responder.getResponderByURL(wsURL);
                if (res != null){
                    mess.setConfiguration(res);
                }
                else{
                    res = new Responder(wsURL, wsURL);
                    res = Responder.persistResponder(res);
                    mess.setConfiguration(res);
                }
            }
            mess = XCPDMessage.persistXCPDMessage(mess);
        }
        if (this.requestV3.equals("")){
            FacesMessages.instance().add("You have to specify a request V3.");
        }
        if (this.wsURL.equals("")){
            FacesMessages.instance().add("You have to specify a responder endpoint.");
        }
    }
    /*
    public void generateResponse() throws Exception{
        if ((!this.requestV3.equals(""))&&(!this.wsURL.equals(""))){
            Client2Server c2s = new Client2Server();
            if (this.assertionType == null){
                this.responseV3 = HL7V3Responder.generateResponse(this.requestV3, this.wsURL, false);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = c2s.createMessageSoap(null, this.requestV3);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
                return;
            }
            if (this.assertionType.equals("none")){
                this.responseV3 = HL7V3Responder.generateResponse(this.requestV3, this.wsURL, false);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = c2s.createMessageSoap(null, this.requestV3);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
            }
            if (this.assertionType.equals("complete_assertion")){
                this.soapRequest = c2s.createMessageSoap(this.completeAssertion, this.requestV3);
                this.responseV3 = SOAPSender2.sendToUrlAndGetResponse(wsURL, this.soapRequest);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
            }
            if (this.assertionType.equals("assertion_from_sts")){
                String assertion = AssertionGenerator.generateToken(this.stsUrl, "ihelocal");
                this.soapRequest = c2s.createMessageSoap(assertion, this.requestV3);
                this.responseV3 = SOAPSender2.sendToUrlAndGetResponse(wsURL, this.soapRequest);
                this.responseV3 = XmlFormatter.prettyFormat(this.responseV3, 3);
                this.soapRequest = XmlFormatter.prettyFormat(this.soapRequest, 3);
            }
            XCPDMessage mess = new XCPDMessage();
            mess.setMessageSentContent(this.soapRequest.getBytes());
            mess.setMessageResponseContent(this.responseV3.getBytes());
            mess.setMessageType("ITI-55");
            mess.setTimeStamp(new Date());
            mess.setTransaction(Transaction.GetTransactionByKeyword("ITI-55"));
            if (this.wsURL != null){
                Responder res = Responder.getResponderByURL(wsURL);
                if (res != null){
                    mess.setConfiguration(res);
                }
                else{
                    res = new Responder(wsURL, wsURL);
                    res = Responder.persistResponder(res);
                    mess.setConfiguration(res);
                }
            }
            mess = XCPDMessage.persistXCPDMessage(mess);
        }
        if (this.requestV3.equals("")){
            FacesMessages.instance().add("You have to specify a request V3.");
        }
        if (this.wsURL.equals("")){
            FacesMessages.instance().add("You have to specify a responder endpoint.");
        }
    }
    */
    
    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";
        }
    }
    
    public List<String> getListWsUrl(){
        List<String> ls = new ArrayList<String>();
       List<Responder> lres = Responder.getListOfResponder();
       if (lres != null){
           for (Responder res:lres){
               ls.add(res.getWsurl());
           }
       }
       return ls;
    }
    
    public void reinitializeAssertion(){
        
    }
    
    /*
    public boolean assertionTypeIsComplete(){
        if (this.assertionType != null){
            if (this.assertionType.equals("complete_assertion")){
                return true;
            }
        }
        return false;
    }
    
    public boolean assertionTypeIsURL(){
        if (this.assertionType != null){
            if (this.assertionType.equals("assertion_from_sts")){
                return true;
            }
        }
        return false;
    }
    */

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

}
