package at.gv.egovernment.moa.spss.server.webservice.impl;

import java.security.cert.X509Certificate;

import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

import at.gv.egovernment.moa.logging.LoggingContext;
import at.gv.egovernment.moa.logging.LoggingContextManager;
import at.gv.egovernment.moa.spss.server.config.ConfigurationException;
import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContext;
import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager;
import at.gv.egovernment.moa.spss.server.transaction.TransactionIDGenerator;

@Aspect
public class ContextSetupAspect {

	private static final Logger logger = LoggerFactory.getLogger(ContextSetupAspect.class);
	
	/** The property name for accessing the X509 client certificate chain. */
	private static final String X509_CERTIFICATE_PROPERTY = "javax.servlet.request.X509Certificate";

	/** The property name for accessing the SOAP action header. */
	private static final String SOAP_ACTION_HEADER = "soapaction";
	
	/**
	 * Set up the thread-local contexts (<code>TransactionContext</code> and
	 * <code>LoggingContext</code>).
	 * 
	 * @param context
	 *            The <code>TransactionContext</code> to set for the current
	 *            request.
	 */
	private static void setUpContexts(TransactionContext context) {
		// set the transaction context in the TransactionContextManager
		TransactionContextManager tcm = TransactionContextManager.getInstance();
		tcm.setTransactionContext(context);

		// set the logging context in the LoggingContextManager
		LoggingContextManager lcm = LoggingContextManager.getInstance();
		LoggingContext lc = new LoggingContext(context.getTransactionID());
		lcm.setLoggingContext(lc);
	}

	/**
	 * Tear down the thread-local contexts.
	 */
	private static void tearDownContexts() {
		TransactionContextManager tcm = TransactionContextManager.getInstance();

		// delete temporary files
		TransactionContext context = tcm.getTransactionContext();
		context.cleanAttachmentCache();

		// unset the transaction context
		tcm.setTransactionContext(null);

		// unset the logging context
		LoggingContextManager lcm = LoggingContextManager.getInstance();
		lcm.setLoggingContext(null);
	}

	public static void setupContext(MessageContext messageContext, String targetService) throws ConfigurationException {
		logger.debug("Context setup");
		
		HttpServletRequest request = (HttpServletRequest) messageContext
				.get(AbstractHTTPDestination.HTTP_REQUEST);

		X509Certificate[] clientCert = (X509Certificate[]) request.getAttribute(X509_CERTIFICATE_PROPERTY);

		ConfigurationProvider configuration = ConfigurationProvider.getInstance();

		Element xmlRequest = null;
		if (messageContext instanceof SOAPMessageContext) {
			SOAPMessageContext soapMessageContext = (SOAPMessageContext) messageContext;
			xmlRequest = soapMessageContext.getMessage().getSOAPPart().getDocumentElement();
		}

		TransactionContext context = new TransactionContext(TransactionIDGenerator.nextID(), clientCert,
				configuration, xmlRequest, null);

		String soapAction = (String) request.getHeader(SOAP_ACTION_HEADER);
		if ("\"\"".equals(soapAction)) {
			// if http soap action header is empty
			soapAction = targetService;
		}
		context.setRequestName(soapAction);
		
		setUpContexts(context);
	}

	public static void cleanContext() {
		logger.debug("Context clean up");
		tearDownContexts();
	}
}