/**
 * 
 */


package gov.va.med.cds.tools.cleanup.errorq;


import gov.va.med.cds.properties.PropertiesUtil;

import java.io.File;
import java.io.IOException;
import java.util.Date;

import javax.xml.parsers.FactoryConfigurationError;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * @author susarlan
 *
 */
public class ErrorQCleanUp
    extends
        Thread
    implements
        ErrorQCleanUpMBeanInterface
{
    private static Log logger = LogFactory.getLog( ErrorQCleanUp.class );
    private static ApplicationContext applicationContext;
    private ErrorQueueDefaultMessageListenerContainer listenerContainer = null;
    private static ErrorQCleanUp instance = null;
    private ErrorQueueCleanUpLogger errorQueueCleanUpLogger;
    private String configFilename = null;
    private long logId = 0;
    private AtomicCounter messageCounter;
    public static final String DEFAULT_JMS_TIMESTAMP_END = "default.jms.timestamp.end"; 


    public enum RuntimeState
    {
        INITIALIZING, RUNNING, SHUTDOWN, TERMINATED
    };

    private RuntimeState runtimeState = RuntimeState.INITIALIZING;

    private static int errorQRunDurationMins = 5;


    /**
     * @param args
     */
    public static void main( String[] args )
    {
    	Date date = ErrorQueueJMSTimestampUtil.getCurrentTimeInDate();
    	String value = ErrorQueueJMSTimestampUtil.formatDateToString(date);
    	System.setProperty(DEFAULT_JMS_TIMESTAMP_END, value);
    	if ( args != null && args.length > 0 && args[0].matches( ".*[xX][mM][lL]$" ) )
        {
            setup( args[0] );
        }
        else
        {
            setup( "classpath:gov/va/med/cds/tools/cleanup/errorq/errorQCleanUpContext.xml" );
        }
        logger.info( "ErrorQCleanup main() finished." );
    }
    
    
    protected static void setup( String cfg )
    {
    	String errorQRunDuration = System.getProperty( "errorq.cleanup.run.duration" );
        
        if ( null != errorQRunDuration || "".equals( errorQRunDuration ) )
        {
            errorQRunDurationMins = Integer.parseInt( errorQRunDuration );
        }

        try
        {
            //configure the runtime environment
            ErrorQCleanUp.configureLoggingAndProperties( logger, System.getProperty( "log4j.configurationFile" ) );
            logger.info( "setup( String cfg ): Starting up ErrorQ CleanUp application with config: " + cfg );
            applicationContext = new ClassPathXmlApplicationContext( cfg );
            instance = ( ErrorQCleanUp )applicationContext.getBean( "errorQCleanUp" );
            instance.configFilename = cfg;
            
            instance.start();
            instance.join( ( errorQRunDurationMins +2 ) * 60 * 1000L );
        }
        catch ( InterruptedException e )
        {
            logger.error( "setup( String cfg ) join interrupted", e );
        }
        catch ( Exception e )
        {
            logger.error( "setup( String cfg )", e );
        }
        finally
        {
            instance.listenerContainer = null;
            instance = null;
        }
    }


    public void run( )
    {
        while ( runtimeState != RuntimeState.TERMINATED )
        {
            switch ( runtimeState )
            {
            case INITIALIZING:
                executeInitStage();
                break;

            case RUNNING:
                executeRunningStage();
                break;

            case SHUTDOWN:
                logger.info( "run(): ErrorQ listenerContainer attempting to shutdown gracefully." );			

                executeShutdownStage();
                break;
                
            case TERMINATED:
            	logger.info( "ErrorQCleanUp has been terminated" );
            	break;
            }
        }

        if ( logger.isDebugEnabled() )
        {
            logger.debug( "run(): End." );
        }
    }


    private void executeInitStage( )
    {
        runtimeState = RuntimeState.RUNNING;
    }


    private void executeRunningStage( )
    {
        logId = logProcessStart( configFilename );
        instance.listenerContainer.start();

        try
        {
            Thread.sleep( errorQRunDurationMins * 60 * 1000L );
        }
        catch ( InterruptedException e )
        {
             e.printStackTrace();
        }

        runtimeState = RuntimeState.SHUTDOWN;
    }


    private void executeShutdownStage( )
    {
        runtimeState = RuntimeState.TERMINATED;
        instance.listenerContainer.shutdown();
        logProcessFinish( logId );
    }


    protected static void configureLoggingAndProperties( Log logger, String logfilePath )
        throws FactoryConfigurationError,
            IOException
    {
    	
    	File logFile = new File( logfilePath );
        
 //       DOMConfigurator.configure( logFile.getAbsolutePath() );
               
        try {
			new PropertiesUtil().loadSystemRunProperties();
		} catch (Exception e) {

			e.printStackTrace();
		}
        
        if ( logger.isDebugEnabled() )
        {
            logger.debug( "configureLoggingAndProperties( Log logger, String logfilePath ): using log file: " + logFile.getAbsolutePath() );
        }
    }

    private long logProcessStart( String configFilename )
    {
        long logId = 0;
        if ( errorQueueCleanUpLogger != null )
        {
            logId = errorQueueCleanUpLogger.logProcessStart( configFilename );
        }
        return logId;
    }

    private void logProcessFinish( long aLogId )
    {
        if ( errorQueueCleanUpLogger != null )
        {
            errorQueueCleanUpLogger.logProcessFinish( aLogId, messageCounter.getCount() );
        }
    }
    
    public void shutdown( )
    {
        instance.listenerContainer.shutdown();
        instance.interrupt();
    }


    public boolean isRunning( )
    {
        return instance.listenerContainer.isRunning();
    }


    public String getStatus( )
    {
        return "ErrorQCleanUp state is " + runtimeState;
    }


    public int getCurrentConsumerCount( )
    {
        int activeConsumerCount = 0;

        if ( null != instance )
        {
            activeConsumerCount = instance.listenerContainer.getActiveConsumerCount();
        }
        return activeConsumerCount;
    }

    
    public void setListenerContainer( ErrorQueueDefaultMessageListenerContainer listenerContainer )
    {
        this.listenerContainer = listenerContainer;
        
    }

    
    public void setErrorQueueCleanUpLogger( ErrorQueueCleanUpLogger errorQueueCleanUpLogger )
    {
        this.errorQueueCleanUpLogger = errorQueueCleanUpLogger;
        
    }

    
    public void setMessageCounter( AtomicCounter messageCounter )
    {
        this.messageCounter = messageCounter;
        
    }
}
