

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


import gov.va.med.cds.exception.ResponseException;
import gov.va.med.cds.response.util.ResponseErrorSectionExtractor;
import gov.va.med.cds.tools.cleanup.errorq.exception.ErrorQCleanupException;
import gov.va.med.mediator.client.messagemediator.JmsMessageMediatorDelegate;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;


public class ClinicalMessageHandler
    implements
        ErrorQMessageHandlerInterface
{

    private static Log logger = LogFactory.getLog( ClinicalMessageHandler.class );

    // check for message date time
    private static String CLINICAL_SQL_STMT = "SELECT COUNT(*) FROM <DYNAMIC_TABLENAME>";

    // injected by Spring
    private JdbcTemplate hdrJdbcTemplate;
    private MessageCommandInterface clinicalMessageCommand;
    private ResponseErrorSectionExtractor responseErrorSectionExtractor;

    

    public String handleMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime, ErrorQueueCleanUpLogger anErrorQueueCleanUpLogger )
    {
        String methodName = "handleMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime ): ";
        if( logger.isDebugEnabled()){
        	logger.debug( methodName + "Begin." );
        }

        // non-duplicate message
        String response;
            
        if ( isDuplicateMessage( hl7Message, clinicalTableName, entityIdentifier, messageDateTime ) )
        {
            String identifierText = " RecordIdentity: " + entityIdentifier.getIdentity() + " RecordNamespaceId: " + entityIdentifier.getNamespaceId()
                                  + " RecordUniversalId: " + entityIdentifier.universalId + " RecordUniversalType: " + entityIdentifier.universalIdType;
            response = "Duplicate message -- " + identifierText + " MessageDateTime: " + messageDateTime;
            
            anErrorQueueCleanUpLogger.logDuplicate( true );//, entityIdentifier, messageDateTime );
            if(logger.isInfoEnabled()){
            	logger.info( response );
            }
        }
        else
        {
            anErrorQueueCleanUpLogger.logDuplicate( false );//, entityIdentifier, messageDateTime );
            
            response = clinicalMessageCommand.execute( hl7Message, true );
            
            if( !JmsMessageMediatorDelegate.SUCCESS.equalsIgnoreCase(response) ){
            	
	            try
	            {
	                responseErrorSectionExtractor.checkForErrorsInResponse( response );
	            }
	            catch ( ResponseException e )
	            {
	                anErrorQueueCleanUpLogger.logCdsExceptionDetail( hl7Message );
	                // if this exception occurrs, get back to parser and clean up message and try again.
	//                HL7_SUPPORT_HAPI_ENCODE_EXCEPTION
	                throw new ErrorQCleanupException( e, "Error in response from CDS.  Response: " + response );
	            }
	            catch ( RuntimeException e )
	            {
	                e.printStackTrace();
	                anErrorQueueCleanUpLogger.logCdsExceptionDetail( hl7Message );
	                throw new ErrorQCleanupException( e, "Problem while checking for errors in response.  Response: " + response );
	            }
           }
        }
        if( logger.isDebugEnabled()){
            logger.debug( methodName + "End." );       	
        }
         return response;
    }

    
    private boolean isDuplicateMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime )
    {
        if ( clinicalTableName.equalsIgnoreCase( "LAB.LAB_TEST_PRM" ) )
        {
            return false; // isDuplicateLabMessage(...) does not nothing except just return false. Eric commented out the call 04/25/2016
            //isDuplicateLabMessage( hl7Message, clinicalTableName, entityIdentifier, messageDateTime );
        }
        else
        {
            return isDuplicateNonLabMessage( hl7Message, clinicalTableName, entityIdentifier, messageDateTime );
        }
    }
/*    
    private boolean isDuplicateLabMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime )
    {
        String methodName = "isDuplicateLabMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime ): ";
        logger.debug( methodName + "Begin." );

        
        logger.debug( methodName + "End." );

        // TODO handle the difference in record unique key between Lab and other domains.
        //
        // CDS returns error which EQCU keeps trying to reprocess because it's an oracle error.
        // Therefore I have added this particular exception to the reprocessing rejection list.
        // SJB

        return false;
    }
  */  
    private boolean isDuplicateNonLabMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime )
    {
        String methodName = "isDuplicateNonLabMessage( String hl7Message, String clinicalTableName, EntityIdentifier entityIdentifier, String messageDateTime ): ";
        if( logger.isDebugEnabled()){
        	logger.debug( methodName + "Begin." );
        }

        StringBuilder sqlStmt = new StringBuilder();
        ArrayList<String> parameters = new ArrayList<String>();

        sqlStmt.append( CLINICAL_SQL_STMT.replaceAll( "<DYNAMIC_TABLENAME>", clinicalTableName ) );
        sqlStmt.append( " WHERE " );

        //check if entityIdentifier has identity value
        if ( null == entityIdentifier.identity || "".equals( entityIdentifier.identity ) )
        {
            sqlStmt.append( " RECORDIDENTIFIER_IDENTITY IS NULL" );
        }
        else
        {
            sqlStmt.append( " RECORDIDENTIFIER_IDENTITY = ?" );
            parameters.add( entityIdentifier.identity );
        }

        //check if entityIdentifier has namespaceId value
        if ( null == entityIdentifier.namespaceId || "".equals( entityIdentifier.namespaceId ) )
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_NAMESPACEID IS NULL" );
        }
        else
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_NAMESPACEID = ?" );
            parameters.add( entityIdentifier.namespaceId );
        }

        // check if entityIdentifier has universalId value
        if ( null == entityIdentifier.universalId || "".equals( entityIdentifier.universalId ) )
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_UNIVERSALID IS NULL" );
        }
        else
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_UNIVERSALID = ?" );
            parameters.add( entityIdentifier.universalId );
        }

        // check if entityIdentifier has universalIdType value
        if ( null == entityIdentifier.universalIdType || "".equals( entityIdentifier.universalIdType ) )
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_UNIVERSTYP IS NULL" );
        }
        else
        {
            sqlStmt.append( " AND RECORDIDENTIFIER_UNIVERSTYP = ?" );
            parameters.add( entityIdentifier.universalIdType );
        }

        // check if messageDateTime is not null
        if ( null == messageDateTime || "".equals( messageDateTime ) )
        {
            sqlStmt.append( " AND RECORD_UPDATE_TM IS NULL" );
        }
        else
        {
            sqlStmt.append( " AND RECORD_UPDATE_TM = ?" );
            parameters.add( messageDateTime );
        }

        // print out the SQL statement for informational purposes.
        if ( logger.isDebugEnabled() )
        {
            logger.debug( methodName + "Duplicate check SQL - " + sqlStmt.toString() + "(" + parameters + ")" );
        }

        int duplicateRecordCount = 0;

        try
        {
            duplicateRecordCount = this.hdrJdbcTemplate.queryForObject( sqlStmt.toString(), parameters.toArray(), Integer.class  );
        }
        catch ( DataAccessException dae )
        {
            logger.error( "Unable to check for duplicates: " + dae.getMessage() );
            throw new ErrorQCleanupException( dae );
        }
        if( logger.isDebugEnabled()){
        	logger.debug( methodName + "End." );
        }

        return duplicateRecordCount > 0;
    }
    

    public void setHdrJdbcTemplate( JdbcTemplate hdrJdbcTemplate )
    {
        this.hdrJdbcTemplate = hdrJdbcTemplate;
    }


    public void setClinicalMessageCommand( MessageCommandInterface clinicalMessageCommand )
    {
        this.clinicalMessageCommand = clinicalMessageCommand;
    }

    
    public void setResponseErrorSectionExtractor( ResponseErrorSectionExtractor responseErrorSectionExtractor )
    {
        this.responseErrorSectionExtractor = responseErrorSectionExtractor;
    }

}
