

package gov.va.med.cds.log4j;


//import org.apache.log4j.spi.LoggingEvent;
//import org.apache.log4j.spi.ThrowableInformation;
import org.apache.logging.log4j.core.LogEvent;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;


/**
 * 
 * @author vhaislthummp
 *
 */
public class ApplicationLogEvent
{
    private Long id;

    private String domainName;

    private String requestId;

    private String message;

    private Date localTime;

    private String severity;

    private String appName;

    private static final String DOMAIN_NAME = "<<domain name>>";
    private static final String REQUEST_ID = "<<request id>>";
    private static final String APP_NAME = "<<app name>>";
    private static final String MESSAGE_DELIMITER = "#";


    public ApplicationLogEvent( )
    {
    }


    /**
     * Use Log4J log event to populate the CDS application log event.
     * @param logEvent 
     */
    public ApplicationLogEvent( LogEvent logEvent )
    {
        String message = ( String )logEvent.getMessage().getFormattedMessage();
        if ( null != message && 0 != message.length() )
        {
            extractData( message );

           //Append throwable information if exists
           Throwable throwableInfo = logEvent.getThrown();
           StringBuilder tempMessage = new StringBuilder();

            if ( throwableInfo != null )
            {
        		String[] reps = render(throwableInfo);
        		if(reps.length>0){
        			
        	
	                tempMessage.append( getMessage() );
	                tempMessage.append( "Appending Throwable information - " );
	                for ( String rep : reps )
	                {
	                    tempMessage.append( rep );
	                }
	                setMessage( tempMessage.toString() );
        		}
            }

            //setMessage(myString);
            setLocalTime( new Date() );
            setSeverity( logEvent.getLevel().toString() );
        }
    }
    
    private String[] render(final Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            throwable.printStackTrace(pw);
        } catch(RuntimeException ex) {
        }
        pw.flush();
        LineNumberReader reader = new LineNumberReader(
                new StringReader(sw.toString()));
        ArrayList<String> lines = new ArrayList<String>();
        try {
          String line = reader.readLine();
          while(line != null) {
            lines.add(line);
            line = reader.readLine();
          }
        } catch(IOException ex) {
            if (ex instanceof InterruptedIOException) {
                Thread.currentThread().interrupt();
            }
            lines.add(ex.toString());
        }
        String[] tempRep = new String[lines.size()];
        lines.toArray(tempRep);
        return tempRep;
    }


    private void extractData( String message )
    {
        if ( !message.contains( MESSAGE_DELIMITER ) )
        {
            this.setDomainName( DOMAIN_NAME );
            this.setRequestId( REQUEST_ID );
            this.setAppName( APP_NAME );
            this.setMessage( message );

        }
        else
        {
            Scanner scanner = new Scanner( message ).useDelimiter( MESSAGE_DELIMITER );
            String value = null;
            
            // 1st position - domainName
            if ( scanner.hasNext() )
            {
                value = scanner.next();
                if ( !StringUtils.hasText( value ) )
                {
                    this.setDomainName( DOMAIN_NAME );
                }
                else
                {
                    this.setDomainName( value );
                }
            }

            // 2end position - RequestId
            if ( scanner.hasNext() )
            {
                value = scanner.next();
                if ( !StringUtils.hasText( value ) )
                {
                    this.setRequestId( REQUEST_ID );
                }
                else
                {
                    this.setRequestId( value );
                }

            }

            // 3rd position - AppName

            if ( scanner.hasNext() )
            {
                value = scanner.next();
                if ( !StringUtils.hasText( value ) )
                {
                    this.setAppName( APP_NAME );
                }
                else
                {
                    this.setAppName( value );
                }

            }

            // 4th position - Exception/Error Message
            if ( scanner.hasNext() )
            {
                this.setMessage( scanner.next() );
            }
            
            scanner.close();
        }
    }


    public String getDomainName( )
    {
        return domainName;
    }


    public void setDomainName( String domainName )
    {
        this.domainName = domainName;
    }


    public String getRequestId( )
    {
        return requestId;
    }


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


    public String getMessage( )
    {
        return message;
    }


    public void setMessage( String message )
    {
        this.message = message;
    }


    public Date getLocalTime( )
    {
        return localTime;
    }


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


    public String getSeverity( )
    {
        return severity;
    }


    public void setSeverity( String severity )
    {
        this.severity = severity;
    }


    public String getAppName( )
    {
        return appName;
    }


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


    public Long getId( )
    {
        return id;
    }
}
