package com.ejie.y41e.webservices;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import com.ejie.y41e.common.exceptions.Y41eRuntimeException;

import n38c.exe.N38API;
import n38i.exe.constantesdist.N38NombresParametrosSesionLDAP;

/**
 * 
 * The type .
 * 
 *  
 *
 */
public class N38TokenServerHandler implements SOAPHandler<SOAPMessageContext> {
    private static final String TOKEN_N38X_QUERY = "//n38";
    private final XPathExpression expression;
    private final TransformerFactory transformerFactory;

    /**
     * Constructor por defecto.
     * 
     * @throws XPathExpressionException
     *             exception
     */
    public N38TokenServerHandler() throws XPathExpressionException {
        // inicializacion de la expresión XPATH
        XPathFactory xpFactory = XPathFactory.newInstance();
        XPath xpath = xpFactory.newXPath();
        this.expression = xpath.compile(TOKEN_N38X_QUERY);
        this.transformerFactory = TransformerFactory.newInstance();
    }

    /**
     * @return Set<Qname>
     */
    @Override
    public Set<QName> getHeaders() {
        return new HashSet<QName>();
    }

    /**
     * @param context
     *            el contexto
     */
    @Override
    public void close(MessageContext context) {
        // Nada que hacer
    }

    /**
     * @see javax.xml.ws.handler.Handler#handleFault(javax.xml.ws.handler.MessageContext)
     * @return boolean
     * @param context
     *            el contexto
     */
    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }

    /**
     * @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
     * @return boolean
     * @param context
     *            el contexto
     */
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        boolean valid = true;
        Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        // solo para los mensajes entrantes
        if (outbound != null && !outbound.booleanValue()) {
            valid = false;
            try {
                // Leer header mensaje SOAP
                SOAPHeader soapHeader = context.getMessage().getSOAPHeader();
                final String xmlSOAPHeader = soapHeader.toString();
                if (xmlSOAPHeader == null || "".equals(xmlSOAPHeader.trim())) {
                    throw new Y41eRuntimeException("La petición XML al WebService tiene la cabecera vacía");
                }
                String tokenN38 = doExtractToken(context.getMessage().getSOAPHeader());
                if (StringUtils.isNotBlank(tokenN38)) {
                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder builder = factory.newDocumentBuilder();
                    Document documentoN38 = builder.parse(new InputSource(new StringReader(tokenN38)));
                    final N38API n38api = new N38API(documentoN38);
                    valid = validarLogin(n38api);
                } else {
                    throw new Y41eRuntimeException("La petición XML al WebService tiene la cabecera vacía");
                }
            } catch (Exception e) {
                throw new Y41eRuntimeException(e);
            }
        }
        return valid;
    }

    /**
     * @param n38api
     *            N38API
     * @return boolean
     */
    private boolean validarLogin(N38API n38api) {
        String[] login = null;
        try {
            login = n38api.n38ItemSesion(N38NombresParametrosSesionLDAP.NOMBRE_N38LOGIN);
        } catch (Exception e) {
            throw new Y41eRuntimeException("El token de XLNETS no es válido " + e);
        }
        if (login != null) {
            String aplic = login[0];
            if (aplic != null) {
                return true;
            } else {
                throw new Y41eRuntimeException("El campo aplicación está vacía");
            }
        } else {
            throw new Y41eRuntimeException("No existe el parámetro n38login");
        }
    }

    /**
     * Extrae el xml correspondiente a la sesión de aplicación.
     * 
     * @param node
     *            node
     * @return String
     * @throws XPathExpressionException
     *             exception
     * @throws TransformerException
     *             exception
     */
    private String doExtractToken(Node node) throws XPathExpressionException, TransformerException {
        String tokenN38 = "";
        // busqueda XPath del nodo n38
        Node tokenN38Node = (Node) expression.evaluate(node, XPathConstants.NODE);
        if (tokenN38Node != null) {
            // convertimos a String el nodo del token
            Source tokenN38NodeSource = new DOMSource(tokenN38Node);
            StringWriter writer = new StringWriter();
            Result result = new StreamResult(writer);
            transformerFactory.newTransformer().transform(tokenN38NodeSource, result);
            tokenN38 = writer.toString();
        }
        return tokenN38;
    }
}