package com.ejie.ad74a.util.webservice;

import java.util.HashSet;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.ejie.ad74a.constantes.Constantes;
import com.ejie.ad74a.util.comun.UtilTokenXlnets;
import com.ejie.ad74a.util.comun.UtilidadesXML;

/**
 * 
 * @author Odei
 * 
 */
public class N38TokenClientHandler implements SOAPHandler<SOAPMessageContext> {
	private TransformerFactory transformerFactory;

	// Codigo de aplicacion usado para generar el token
	private String codigoAplicacionToken;

	private static final Logger logger = LoggerFactory.getLogger(N38TokenClientHandler.class);

	/**
	 * Constructor por defecto
	 */
	public N38TokenClientHandler() {
		this.transformerFactory = TransformerFactory.newInstance();
		// Por defecto se usa el codigo de AD74A para generar el token
		codigoAplicacionToken = Constantes.COD_APLICACION;
	}

	/**
	 * Method 'setCodigoAplicacionToken'.
	 *
	 * @param codigoAplicacionToken {@link String}
	 */
	public void setCodigoAplicacionToken(String codigoAplicacionToken) {
		this.codigoAplicacionToken = codigoAplicacionToken;
	}

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

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

	/**
	 * @param context SOAPMessageContext
	 * @return boolean
	 */
	public boolean handleFault(SOAPMessageContext context) {
		return true;
	}

	/**
	 * @param context SOAPMessageContext
	 * @return boolean
	 */
	public boolean handleMessage(SOAPMessageContext context) {
		boolean valid = true;
		Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		// Se saca por traza la comunicacion de entrada/salida a webservices
		log(context);
		// solo para los mensajes SALIENTES
		if (outbound != null && outbound.booleanValue()) {
			valid = false;
			try {
				// crear token n38 de aplicacion
				Document token = null;
				N38TokenClientHandler.logger.debug("PRE - UtilTokenXlnets.getTokenDocumentXLNets('{}')",
						codigoAplicacionToken);
				token = UtilTokenXlnets.getTokenDocumentXLNets(codigoAplicacionToken);
				N38TokenClientHandler.logger.debug("POST - UtilTokenXlnets.getTokenDocumentXLNets('{}')",
						codigoAplicacionToken);
				// recuperar cabecera SOAP
				SOAPHeader soapHeader = context.getMessage().getSOAPHeader();
				// incluir token en la cabecera creada
				Source source = new DOMSource(token);
				Result result = new DOMResult(soapHeader);
				this.transformerFactory.newTransformer().transform(source, result);
				// se puede continuar el procesamiento
				valid = true;
			} catch (Exception e) {
				if (N38TokenClientHandler.logger.isErrorEnabled()) {
					N38TokenClientHandler.logger.error("Error en la inserción del token de seguridad en la cabecera",
							e);
				}
				valid = false;
			}
		}
		return valid;
	}

	/*
	 * Registra por traza la llamada/respuesta del servicio
	 */
	private void log(SOAPMessageContext context) {
		if (N38TokenClientHandler.logger.isDebugEnabled()) {
			Boolean saliente = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
			saliente = saliente != null && saliente.booleanValue();
			try {
				String modo = saliente.booleanValue() ? "saliente" : "entrante";
				N38TokenClientHandler.logger.debug(
						"Mensaje Soap {} (no se muestra token en la cabecera de la llamada):\r\n{}", modo,
						UtilidadesXML.parseDocument2String(context.getMessage().getSOAPBody().getOwnerDocument()));
			} catch (SOAPException e) {
				N38TokenClientHandler.logger.warn("Error al obtener la traza de mensaje ", e);
			}
		}
	}
}