package net.ihe.xcpd.resp.action;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
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.model.Message;
import net.ihe.gazelle.simulator.common.model.TestInstanceParticipants;
import net.ihe.xcpd.resp.model.MessageUser;
import net.ihe.xcpd.resp.model.XCPDMessage;
import net.ihe.xcpd.resp.tools.ElementString;
import net.ihe.xcpd.resp.tools.XmlFormatter;

import org.hl7.v3.PRPAIN201305UV02;
import org.jboss.seam.Component;
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;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


/**
 * @author abderrazek boufahja
 *
 */
@Stateful
@Name("transactionManager")
@Scope(ScopeType.SESSION)
public class TransactionManager implements TransactionManagerLocal,Serializable {

	
	
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    @Logger
	private static Log log;
    
    private Message selectedMessage;
    
    private String selectedMessageStringValue;
    
    private String resultValidation;
    
    private XCPDMessage selectedXCPDMessage;
    
    private XCPDMessageDataModel foundsXCPDMessageDataModel;
    
    ///////////////////////////////////////////
    
    public void setFoundsXCPDMessageDataModel(XCPDMessageDataModel foundsXCPDMessageDataModel) {
        this.foundsXCPDMessageDataModel = foundsXCPDMessageDataModel;
    }

    public XCPDMessageDataModel getFoundsXCPDMessageDataModel() {
        if (foundsXCPDMessageDataModel == null){
            this.foundsXCPDMessageDataModel = new XCPDMessageDataModel(); 
        }
        return foundsXCPDMessageDataModel;
    }

    public XCPDMessage getSelectedXCPDMessage() {
        return selectedXCPDMessage;
    }

    public void setSelectedXCPDMessage(XCPDMessage selectedXCPDMessage) {
        this.selectedXCPDMessage = selectedXCPDMessage;
    }

    public void setSelectedMessageStringValue(String selectedMessageStringValue) {
        this.selectedMessageStringValue = selectedMessageStringValue;
    }

    public String getSelectedMessageStringValue() {
        return selectedMessageStringValue;
    }

    public String getResultValidation() {
        return resultValidation;
    }

    public void setResultValidation(String resultValidation) {
        this.resultValidation = resultValidation;
    }

	public void setSelectedMessage(Message selectedMessage) {
        this.selectedMessage = selectedMessage;
    }

    public Message getSelectedMessage() {
        return selectedMessage;
    }

    public List<net.ihe.gazelle.simulator.common.model.Message> getListOfAllMessage(){
		return net.ihe.gazelle.simulator.common.model.Message.getListOfAllMessage();
	}
	
	public String getSenderApplication(net.ihe.gazelle.simulator.common.model.Message msg){
		String result = new String();
		TestInstanceParticipants sender = msg.getTestInstanceParticipantsSender();
		if (sender == null){
			result = "XCPD RESP simulator";
		}
		else{
			result = sender.getSystem().getKeyword();
		}
		return result;
	}
	
	public String getReceiverApplication(net.ihe.gazelle.simulator.common.model.Message msg){
		String result = new String();
		TestInstanceParticipants receiver = msg.getTestInstanceParticipantsReceiver();
		if (receiver == null){
			result = "XCPD RESP simulator";
		}
		else{
			result = receiver.getSystem().getKeyword();
		}
		return result;
	}
	
	public String getDate(Date tsp){
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss" );
		String s = sdf.format(tsp);
		return s;
	}
	
	public String getMessageBegin(String resmsg){
        String res = new String();
        if (resmsg != null){
            int max = 200;
            if (resmsg.length()<200) {
                max = resmsg.length();
            }
            res = resmsg.substring(0, max) + "...   ";
        }
        return res;
    }
	
	public String getFormattedMessage(){
	    if (this.selectedMessage != null){
	        return this.selectedMessage.getStringValue();
	    }
	    return null;
	}
	
	public String getIpAddress(Message msg){
	    String res = new String();
	    List<MessageUser> lmu = MessageUser.getMessageUserFiltred(null, null, null, msg);
	    if (lmu != null){
	        if (lmu.size()>0){
	            res = lmu.get(0).getIp();
	            if (lmu.get(0).getIpToCountry() != null){
	                res = res + " ( " + lmu.get(0).getIpToCountry().getCountryName() + " )";
	            }
	        }
	    }
	    return res;
	}
	
	
	///////////////////////////////////////
	
	public List<XCPDMessage> getListOfAllXCPDMessage(){
	    return XCPDMessage.getAllMessages();
	}
	
	public void externalRequestSoapValidation(String request){
        String req = this.extractRequestFromSoap(request);
        if (req == null){
            this.resultValidation = null;
            return;
        }
        this.setResultValidation(HL7V3Validator.getValidationResultV3("epSOS - Identification Service (request)", req));
    }
    
    public void externalResponseSoapValidation(String response){
        String res = this.extractResponseFromSoap(response);
        if (res == null){
            this.resultValidation = null;
            return;
        }
        this.setResultValidation(HL7V3Validator.getValidationResultV3("epSOS - Identification Service (response)", res));
    }
    
    public String extractRequestFromSoap(String soapRequest){
        return this.extractFromSoap(soapRequest, "PRPA_IN201305UV02");
    }
    
    public String extractResponseFromSoap(String soapResponse){
        return this.extractFromSoap(soapResponse, "PRPA_IN201306UV02");
    }
    
    private String extractFromSoap(String soapRequest, String node){
        String res = null;
        try {
            String req = ElementString.getRealElementString(soapRequest);
            Element ee = ElementString.string2Element0(req);
            NodeList nl = ee.getElementsByTagNameNS("urn:hl7-org:v3", node);
            if (nl != null){
                if (nl.item(0) != null){
                    Node prpa = nl.item(0);
                    try {
                        res = XmlFormatter.formatNode(prpa);
                        return res;
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                }
                else{
                    if (ee.getTagName().equals(node)){
                        return req;
                    }   
                    
                }
            }
            else{
                if (ee.getTagName().equals(node)){
                    return req;
                }   
            }
            nl.item(0);
        } catch (SAXException e) {
            return null;
        } catch (IOException e) {
            return null;
        }
        return res;
    }
    
    public String getIpAdress(XCPDMessage msg){
        String res = new String();
        res = res + msg.getIp();
        if (msg.getIpToCountry() != null){
            if (msg.getIpToCountry().getCountryName() != null){
                res = res + " ( " + msg.getIpToCountry().getCountryName() + " ) ";
            }
        }
        if (msg.getTestInstanceParticipantsSender() != null){
            res = res + "<br />";
            res = res + msg.getTestInstanceParticipantsSender().getSystem().getKeyword();
        }
        return res;
    }
    
    private String getReceivedStringValue(byte[] messageReceivedContent){
        if (messageReceivedContent == null) return null;
        String msgHL7 = new String(messageReceivedContent);
        return msgHL7;
    }
    
    private String getRespStringValue(byte[] messageResponseContent){
        if (messageResponseContent == null) return null;
        String msgHL7 = new String(messageResponseContent);
        return msgHL7;
    }
    
    public boolean canValidateMesageHL7V3Received(XCPDMessage msg){
        boolean res = false;
        String re = this.getReceivedStringValue(msg.getMessageReceivedContent());
        String req = this.extractRequestFromSoap(re);
        if (req != null) return true;
        return res;
    }
	
    public boolean canViewResponseFromSoap(XCPDMessage currentMessage){
        String res = this.getReceivedStringValue(currentMessage.getMessageReceivedContent());
        if (res.contains("PRPA_IN201306UV02")){
            return true;
        }
        return false;
    }
    
    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()) ;
            return tmp;
        } catch (Exception e) {
            e.printStackTrace( );
            return "The document cannot be displayed using this stylesheet";
        }
    }
    
    public void updateOldMessage(){
        List<MessageUser> lmsg = MessageUser.getListOfAllMessageUser();
        MonComparator c = new MonComparator();
        Collections.sort(lmsg, c);
        for (int i=0;i<lmsg.size(); i++){
            MessageUser msg = lmsg.get(i);
            log.info("mssgid = " + msg.getId());
            String msgContent = null;
            if ( msg.getMessage() != null){
                msgContent = msg.getMessage().getStringValue();
            }
            PRPAIN201305UV02 pr5 = StringTransformer.String2PRPAIN201305UV02(msgContent);
            if (pr5 != null){
                XCPDMessage xcpdmsg = new XCPDMessage();
                xcpdmsg.setIp(msg.getIp());
                xcpdmsg.setIpToCountry(msg.getIpToCountry());
                if (msg.getMessage() != null){
                    xcpdmsg.setMessageReceivedContent(msg.getMessage().getMessageContent());
                    xcpdmsg.setMessageType(msg.getMessage().getMessageType());
                    xcpdmsg.setTestInstanceParticipantsSender(msg.getMessage().getTestInstanceParticipantsSender());
                    xcpdmsg.setTimeStamp(msg.getMessage().getTimeStamp());
                    xcpdmsg.setTransaction(msg.getMessage().getTransaction());
                }
                if ((i+1)<lmsg.size()){
                    PRPAIN201305UV02 pr6 = null;
                    if (lmsg.get(i + 1).getMessage() != null){
                        pr6 = StringTransformer.String2PRPAIN201305UV02(lmsg.get(i + 1).getMessage().getStringValue());
                    }
                    if (pr6 != null){
                        if (lmsg.get(i + 1).getIp() != null){
                            if (lmsg.get(i + 1).getIp().equals(msg.getIp())){
                                xcpdmsg.setMessageResponseContent(lmsg.get(i + 1).getMessage().getMessageContent());
                            }
                        }
                        else if (msg.getIp() == null){
                            xcpdmsg.setMessageResponseContent(lmsg.get(i + 1).getMessage().getMessageContent());
                        }
                    }
                }
                EntityManager entityManager=(EntityManager)Component.getInstance("entityManager");
                List<XCPDMessage> lxcpdmsg = XCPDMessage.getAllMessages();
                if (!lxcpdmsg.contains(xcpdmsg)){
                    xcpdmsg = entityManager.merge(xcpdmsg);
                    entityManager.flush();
                    log.info("id of new msg = " + xcpdmsg.getId());
                }
            }
        }
    }
    
    public void initializeXCPDMessage(){
        FacesContext fc = FacesContext.getCurrentInstance();
        String id = (String) fc.getExternalContext().getRequestParameterMap().get("id");
        EntityManager entityManager=(EntityManager)Component.getInstance("entityManager");
        try{
            Integer idd = Integer.valueOf(id);
            this.selectedXCPDMessage = entityManager.find(XCPDMessage.class, idd);
        }
        catch(Exception e){
            FacesMessages.instance().add("You have to add a good id.");
            this.selectedXCPDMessage = null;
            return;
        }
    }
    
    public String generateLinkForSelectedXCPDMessage(){
        return this.generateLinkForXCPDMessage(this.selectedXCPDMessage);
    }
    
    public String generateLinkForXCPDMessage(XCPDMessage mss){
        if (mss != null && mss.getId() != null){
            String url = ApplicationConfiguration.getValueOfVariable("url");
            return url + "/transaction.seam?id=" + mss.getId();
        }
        return null;
    }
	
    public void findXCPDMessageCreated() 
    {
       log.info("Find all HL7 messages!");
       this.foundsXCPDMessageDataModel = new XCPDMessageDataModel(); 
       log.info("hl7MessageDataModel.getRowCount() : " + foundsXCPDMessageDataModel.getRowCount());
    }
	
	///////////////////////////////////////

	@Destroy
	@Remove
	public void destroy()
	{
		log.info("destroy");
	}
	
	class MonComparator implements Comparator<MessageUser>
	{
	    MonComparator()
	    {
	    }

        @Override
        public int compare(MessageUser o1, MessageUser o2) {
            if (o1.getId().compareTo(o2.getId())>0) return 1;
            if (o1.getId().compareTo(o2.getId())<0) return -1;
            return 0;
        }

	}

}
