package com.ejie.ab04b.remoting.jaxws;

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

import javax.xml.namespace.QName;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;

/**
 * @author GFI-NORTE
 * 
 */
public class N38TokenServerHandler implements SOAPHandler<SOAPMessageContext> {
	private static final Logger LOGGER = LoggerFactory
			.getLogger(N38TokenServerHandler.class);

	private String tokenN38XQuery = "//n38";
	private XPathExpression expression;
	private TransformerFactory transformerFactory;

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

	/**
	 * Gets the headers.
	 * 
	 *  Set<QName>
	 *
	 * @return the headers
	 */
	public Set<QName> getHeaders() {
		return new HashSet<QName>();
	}

	/**
	 * Close.
	 * 
	 *  context            MessageContext
	 *
	 * @param context the context
	 */
	public void close(MessageContext context) {
		// Nada que hacer
	}

	/**
	 * Handle fault.
	 * 
	 *  context            SOAPMessageContext
	 *  boolean
	 *
	 * @param context the context
	 * @return true, if successful
	 */
	public boolean handleFault(SOAPMessageContext context) {
		return true;
	}

	/**
	 * Handle message.
	 * 
	 *  context            SOAPMessageContext
	 *  boolean
	 *
	 * @param context the context
	 * @return true, if successful
	 */
	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 {
				String tokenN38 = doExtractToken(context.getMessage()
						.getSOAPHeader());
				if (tokenN38 != null && !tokenN38.equals("")) {
					// TODO verificar que la sesion es valida
					// TODO verificar los permisos del cliente
					// En el ejemplo unicamente comprobamos que se ha enviado
					// una sesion de aplicacion
					valid = true;
				}
			} catch (Exception e) {
				N38TokenServerHandler.LOGGER
						.error("[ERROR] Fallo en handleMessage");
			}
		}
		return valid;
	}

	/**
	 * Extrae el xml correspondiente a la sesión de aplicación.
	 * 
	 *  node
	 *            Node
	 *  String
	 *
	 * @param node the node
	 * @return the string
	 * @throws XPathExpressionException             XPathExpressionException
	 * @throws TransformerException             TransformerException
	 */
	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;
	}
}