package com.fp.common.soap;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.net.URL;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPMessage;

import org.apache.log4j.Logger;
import org.apache.xml.serializer.ToXMLStream;
import org.w3c.dom.Node;

import com.fp.common.files.StreamHelper;
import com.fp.common.properties.PropertiesHandler;

public final class WSClient {
    private static final Logger LOG = Logger.getLogger(WSClient.class);

    /** Instancia singleton de SOAPClient */
    private static WSClient instance = null;

    /**
     * Obtiene la instancia singleton de SOAPClient
     * 
     * @return singleton
     */
    public static WSClient getInstance() {
        synchronized (WSClient.class) {
            if (WSClient.instance == null) {
                WSClient.instance = new WSClient();
            }
        }
        return WSClient.instance;
    }

    /**
     * Contructor sin parametros
     */
    private WSClient() {
    }

    /**
     * Envia una peticion SOAP en base a los parametros definido en el PropertiesHandler
     * 
     * @param pEndpintURL
     * @param pSoapRequest
     * @param ph
     * @return data resultado de la peticion
     * @throws Exception
     */
    public String soapSend(String pEndpintURL, String pSoapRequest, PropertiesHandler ph) throws Exception {
        try {
            WSClient.LOG.debug("ENDPOINT " + pEndpintURL);

            String file = ph.getStringValue("ws.ofac.path") + "/FL" + Double.valueOf(Math.random() * 100000).intValue()
                    + ".txt";

            FileOutputStream fout = new FileOutputStream(file);
            try {
                fout.write(pSoapRequest.getBytes());
            } finally {
                fout.close();
            }

            String command = ph.getStringValue("ws.ofac.command") + " " + pEndpintURL + " " + file;

            /*
             * Descomentar para pruebas en Windows String command =File.separator
             * +"Fitbank"+File.separator+"soap"+File.separator+"run.bat" + " " + EndpintURL + " " + file;
             */

            Process p = Runtime.getRuntime().exec(command);

            String data = StreamHelper.readStream(p.getInputStream());
            WSClient.LOG.debug("Respuesta |" + data + "|");
            return data;
        } catch (Exception e) {
            WSClient.LOG.error(e, e);
            throw e;
        }
    }

    public SOAPMessage prepareMessage(String pSoapRequest) throws Exception {
        return this.prepareMessage(pSoapRequest, "ISO-8859-1");
    }

    /**
     * Prepara el mensaje SOAP a ser enviado
     * 
     * @param pSoapRequest
     * @return
     * @throws Exception
     */
    public SOAPMessage prepareMessage(String pSoapRequest, String pEncoding) throws Exception {
        MessageFactory msgFactory = MessageFactory.newInstance();
        WSClient.LOG.debug("MessageFactory |" + msgFactory.getClass().getName() + "|");
        return msgFactory.createMessage(null, new ByteArrayInputStream(
        // ("<?xml version='1.0' encoding='ISO-8859-1'?>" + pSoapRequest).getBytes()));
                ("<?xml version='1.0' encoding='" + pEncoding + "'?>" + pSoapRequest).getBytes()));
    }

    /**
     * Envia una peticion SOAP para pruebas mediante una nueva conexion
     * 
     * @param pEndpintURL
     * @param pSoapRequest
     * @return resp
     * @throws Exception
     */
    public String soapSendReal(String pEndpintURL, String pSoapRequest) throws Exception {
        WSClient.LOG.debug("EndPoint |" + pEndpintURL + "| Peticion |" + pSoapRequest + "|");
        // MessageFactory msgFactory = new MessageFactoryImpl();
        SOAPConnection con = SOAPConnectionFactory.newInstance().createConnection();
        SOAPMessage reqMsg = this.prepareMessage(pSoapRequest);
        URL epURL = new URL(pEndpintURL);
        SOAPMessage resMsg = con.call(reqMsg, epURL);
        String resp = WSClient.nodeToString(resMsg.getSOAPBody().getOwnerDocument());
        WSClient.LOG.debug(" Respuesta |" + resp + "|");
        return resp;
    }

    public static String nodeToString(Node pNode) throws Exception {
        String data = "";
        ToXMLStream dser = (ToXMLStream) (new ToXMLStream()).asDOMSerializer();

        StringWriter sw = new StringWriter();
        dser.setWriter(sw);
        dser.serialize(pNode);
        String element = sw.toString();
        data = element.substring(element.indexOf(">") + 1);
        return data;
    }
}