/**
 * 
 */


package gov.va.med.cds.audit;


import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;

import gov.va.med.cds.util.DateTimeUtil;


/**
 * @author DNS   egberb
 * 
 */
public abstract class AbstractAuditLog
    implements
        Serializable
{
    private static final Log logger = LogFactory.getLog( AbstractAuditLog.class );
    private static final long serialVersionUID = 1L;

    protected static final String ADD_NEW_LINE = "\n";
    protected static final String ADD_TAB = "\t";
    protected static final String ADD_DOUBLE_TAB = "\t\t";
    private static final String DOMAIN_NAME = "CDS v3.x";

    private Long auditLogId;

    private Date localTime;

    protected String isoLocalTime = DateTimeUtil.getISOTime( new Date().getTime(), null );
    private ClientMapping clientMapping;
    private String clientId;
    private String clientRequestInitiationTime;
    private TemplateIdWrapper templateId = new TemplateIdWrapper();
    protected String filterRequest;
    private FilterIdWrapper filterId = new FilterIdWrapper();
    private String facility;
    private String response;
    protected long startTime;
    protected long endTime;
    private long milliseconds;
    protected String requestId;
    protected String sendingApplication;
    protected String debugInfo;
    private int responseSize = -1;
    private int responseLength = -1;
    private String machine;
    private String appName;


    public int getResponseSize( )
    {
        if ( responseSize < 0 )
        {
            responseSize = ( response != null ) ? response.getBytes().length : 0;
        }
        
        return responseSize;
    }


    public void setResponseSize( int responseSize )
    {
        this.responseSize = responseSize;
    }


    public int getResponseLength( )
    {
        if ( responseLength < 0 )
        {
            responseLength = getResponseLength( response );
        }
        
        return responseLength;
    }


    public void setResponseLength( int responseLength )
    {
        this.responseLength = responseLength;
    }


    public String getMachine( )
    {
        if ( machine == null )
        {
            try
            {
                machine = InetAddress.getLocalHost().getHostName();
            }
            catch ( UnknownHostException uhe )
            {
            }
        }

        return machine;
    }


    public void setMachine( String machine )
    {
        this.machine = machine;
    }


    public Long getAuditLogId( )
    {
        return auditLogId;
    }


    @SuppressWarnings( "unused" )
    private void setAuditLogId( Long auditLogId )
    {
        this.auditLogId = auditLogId;
    }


    public String getDebugInfo( )
    {
        StringBuilder auditInfo = new StringBuilder();

        // Build the audit log message
        auditInfo.append( "Server CDS v3.x ==> Audit detail: " );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_TAB );
        auditInfo.append( "domain => " );
        auditInfo.append( DOMAIN_NAME );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_TAB );
        auditInfo.append( "start_milliseconds => " );
        auditInfo.append( startTime );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_TAB );
        auditInfo.append( "milliseconds => " );
        auditInfo.append( getMilliseconds() );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_TAB );
        auditInfo.append( "ISO_localtime => " );
        auditInfo.append( isoLocalTime );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_TAB );
        auditInfo.append( "log_information => " );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "startTime -> " );
        auditInfo.append( startTime );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "sendingApplication -> " );
        auditInfo.append( sendingApplication );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "originalMessageControlId -> " );
        auditInfo.append( requestId );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "requesterString -> " );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "requestMsg -> " );
        auditInfo.append( filterRequest );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "receivingApplication -> " );
        auditInfo.append( "CDS v3.x" );
        auditInfo.append( ADD_NEW_LINE );
        auditInfo.append( ADD_DOUBLE_TAB );
        auditInfo.append( "completionTime -> " );
        auditInfo.append( Long.toString( endTime ) );

        this.debugInfo = auditInfo.toString();
        return debugInfo;
    }


    public void setDebugInfo( String debugInfo )
    {
        this.debugInfo = debugInfo;
        Map<String, String> debugInfoMap = parseDebugInfo( debugInfo );
        setStartTime( Long.parseLong( debugInfoMap.get( "start_milliseconds" ) ) );
        setMilliseconds( Long.parseLong( debugInfoMap.get( "milliseconds" ) ) );
        setIsoLocalTime( debugInfoMap.get( "ISO_localtime" ) );
        setSendingApplication( debugInfoMap.get( "sendingApplication" ) );
        setRequestId( debugInfoMap.get( "originalMessageControlId" ) );
        setFilterRequest( debugInfoMap.get( "requestMsg" ) );
        setEndTime( Long.parseLong( debugInfoMap.get( "completionTime" ) ) );
    }


    public String getDomainName( )
    {
        return DOMAIN_NAME;
    }


    public ClientMapping getClientMapping( )
    {
        return clientMapping;
    }


    public void setClientMapping( ClientMapping aClientMapping )
    {
        this.clientMapping = aClientMapping;
    }


    public String getFilterId( )
    {
        return filterId.getFilterId();
    }


    public String getClientId( )
    {
        return clientId;
    }


    public void setClientId( String clientId )
    {
        this.clientId = clientId;
    }


    public FilterIdWrapper getFilterIdWrapper( )
    {
        return filterId;
    }


    public String getTemplateId( )
    {
        return templateId.getTemplateId();
    }


    public TemplateIdWrapper getTemplateIdWrapper( )
    {
        return templateId;
    }


    public void setFilterIdWrapper( FilterIdWrapper aFilterIdWrapper )
    {
        filterId = aFilterIdWrapper;
    }


    public void setTemplateIdWrapper( TemplateIdWrapper aTemplateIdWrapper )
    {
        templateId = aTemplateIdWrapper;
    }


    public void setTemplateId( String aTemplateId )
    {
        templateId.setTemplateId( aTemplateId );
        if ( clientMapping == null )
        {
            clientMapping = new ClientMapping( null, aTemplateId );
        }
        else
        {
            clientMapping.setTemplateId( aTemplateId );
        }
    }


    public String getFilterRequest( )
    {
        return filterRequest;
    }


    public void setFilterRequest( String filterRequest )
    {
        this.filterRequest = filterRequest;
        try
        {
            Document filterDocument = DocumentHelper.parseText( filterRequest );
            this.setClientId( filterDocument.getRootElement().elementTextTrim( "clientName" ) );
            this.setClientRequestInitiationTime( filterDocument.getRootElement().elementTextTrim( "clientRequestInitiationTime" ) );
        }
        catch ( DocumentException e )
        {
            throw new IllegalArgumentException( "Filter request document is not valid XML.", e );
        }
    }


    public void setFilterId( String aFilterId )
    {
        filterId.setFilterId( aFilterId );
        if ( clientMapping == null )
        {
            clientMapping = new ClientMapping( aFilterId, null );
        }
        else
        {
            clientMapping.setFilterId( aFilterId );
        }
    }


    public String getRequestId( )
    {
        return requestId;
    }


    public void setRequestId( String requestId )
    {
        this.requestId = requestId;
    }


    public String getResponse( )
    {
        return response;
    }


    public void setResponse( String response )
    {
        this.response = response;
    }


    public long getStartTime( )
    {
        return startTime;
    }


    public void setStartTime( long startTime )
    {
        this.startTime = startTime;
    }


    public long getEndTime( )
    {
        return endTime;
    }


    public void setEndTime( long endTime )
    {
        this.endTime = endTime;
    }


    public String getFacility( )
    {
        return facility;
    }


    public void setFacility( String facility )
    {
        this.facility = facility;
    }


    public String getIsoLocalTime( )
    {
        return isoLocalTime;
    }


    public void setIsoLocalTime( String isoLocalTime )
    {
        this.isoLocalTime = isoLocalTime;
    }


    public Date getLocalTime( )
    {
        return localTime;
    }


    public void setLocalTime( Date localTime )
    {
        this.localTime = localTime;
    }


    public long getMilliseconds( )
    {
        this.milliseconds = this.endTime - this.startTime;
        return this.milliseconds;
    }


    public void setMilliseconds( long milliseconds )
    {
        this.milliseconds = milliseconds;
    }


    public String getSendingApplication( )
    {
        return sendingApplication;
    }


    public void setSendingApplication( String sendingApplication )
    {
        this.sendingApplication = sendingApplication;
    }


    public void setAppName( String appName )
    {
        this.appName = appName;
    }


    protected Map<String, String> parseDebugInfo( String debugInfo )
    {
        Map<String, String> data = new Hashtable<String, String>();
        String delim = "=>";
        debugInfo = debugInfo.substring( debugInfo.indexOf( "Audit detail: " ) + "Audit detail: ".length() );
        String[] infos = debugInfo.split( "\n" );

        for ( String info : infos )
        {
            info = info.trim();

            if ( info.startsWith( "Server" ) )
            {
                continue;
            }

            if ( info.startsWith( "log_information" ) )
            {
                delim = "->";
                continue;
            }

            String[] arr = info.split( delim );
            data.put( arr[0].trim(), ( arr.length == 2 ) ? arr[1].trim() : "" );
        }

        return data;
    }


    protected abstract int getResponseLength( String response );


    public String getAppName( )
    {
        return appName;
    }


    public String getClientRequestInitiationTime( )
    {
        return clientRequestInitiationTime;
    }


    public void setClientRequestInitiationTime( String clientRequestInitiationTime )
    {
        this.clientRequestInitiationTime = clientRequestInitiationTime;
    }

}
