package gov.va.med.esr.webservices.jaxws.spring.interceptor;

import gov.va.med.esr.model.ServiceLog;
import gov.va.med.esr.service.ServiceLogService;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.xml.transform.TransformerObjectSupport;

public class DBLoggingInterceptor extends TransformerObjectSupport
    implements EndpointInterceptor
{
	
	private ServiceLogService serviceLogService;

    public ServiceLogService getServiceLogService() {
		return serviceLogService;
	}

	public void setServiceLogService(ServiceLogService serviceLogService) {
		this.serviceLogService = serviceLogService;
	}

	public DBLoggingInterceptor()
    {
        logger = LogFactory.getLog(getClass());
        logRequest = true;
        logResponse = true;
    }

    public final void setLogRequest(boolean logRequest)
    {
        this.logRequest = logRequest;
    }

    public final void setLogResponse(boolean logResponse)
    {
        this.logResponse = logResponse;
    }

    public void setLoggerName(String loggerName)
    {
        logger = LogFactory.getLog(loggerName);
    }

    public final boolean handleRequest(MessageContext messageContext, Object endpoint)
        throws TransformerException
    {
        if(logRequest && isLogEnabled())
            logMessageSource("Request: ", getSource(messageContext.getRequest()));
        
        
       	ServiceLog serviceLog = new ServiceLog();
    	serviceLog.setRequestDate(new Date());
    	
    	String request = convertSource(getSource(messageContext.getRequest()));
    	serviceLog.setRequest(request);
    	
    	MessageContextHolder.setServiceLog(serviceLog);
        
        return true;
    }

    public boolean handleResponse(MessageContext messageContext, Object endpoint)
        throws Exception
    {
        if(logResponse && isLogEnabled())
            logMessageSource("Response: ", getSource(messageContext.getResponse()));
        
        Date currDate = new Date();
        
        
        ServiceLog serviceLog = MessageContextHolder.getServiceLog();
        serviceLog.setResponseTime(currDate.getTime() - serviceLog.getRequestDate().getTime());
        serviceLog.setUser(MessageContextHolder.getServiceUser());
                
        Exception ex = MessageContextHolder.getException();
        if ( ex != null )
        {
        	serviceLog.setErrorText(ex.getMessage());
        }
        serviceLogService.saveLog(serviceLog);
    
        return true;
    }

    public boolean handleFault(MessageContext messageContext, Object endpoint)
        throws Exception
    {
        return handleResponse(messageContext, endpoint);
    }

    protected boolean isLogEnabled()
    {
        return logger.isDebugEnabled();
    }

    private Transformer createNonIndentingTransformer()
        throws TransformerConfigurationException
    {
        Transformer transformer = createTransformer();
        transformer.setOutputProperty("omit-xml-declaration", "yes");
        transformer.setOutputProperty("indent", "no");
        return transformer;
    }

    
    private String convertSource(Source source) throws TransformerException
    {
        if(source != null)
        {
            Transformer transformer = createNonIndentingTransformer();
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String message = (new StringBuilder()).append(writer.toString()).toString();
            logMessage(message);
            return message;
        }
        return null;
    }
    
    protected void logMessageSource(String logMessage, Source source)
        throws TransformerException
    {
        if(source != null)
        {
            Transformer transformer = createNonIndentingTransformer();
            StringWriter writer = new StringWriter();
            transformer.transform(source, new StreamResult(writer));
            String message = (new StringBuilder()).append(logMessage).append(writer.toString()).toString();
            logMessage(message);
        }
    }

    protected void logMessage(String message)
    {
        logger.debug(message);
    }

    protected Source getSource(WebServiceMessage message)
    {
        return message.getPayloadSource();
    }
    
	protected String getExceptionStackTrace(Throwable exception) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		exception.printStackTrace(pw);
		pw.close();
		return sw.getBuffer().toString();
	}

    protected transient Log logger;
    private boolean logRequest;
    private boolean logResponse;

}
