

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


import gov.va.med.hds.hdr.busobj.patient.Patient;
import gov.va.med.hds.hdr.busobj.patient.PatientBuilderException;
import gov.va.med.hds.hdr.busobj.patient.PatientIdentifier;
import gov.va.med.hds.hdr.busobj.patient.XMLPatientBuilder;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;


public class PsimGraphMessageHandler
{
    private Log logger = LogFactory.getLog( PsimGraphMessageHandler.class );

    private String graphWithLocalAndNationalIdentifier = "SELECT COUNT (*) FROM domain_id WHERE domain = :localIdentifierDomain AND domain_id = :localIdentifier AND "
                    + "correlated_id IN (SELECT correlated_id FROM domain_id WHERE domain_id = :nationalIdentifier)";

    private String graphWithCorrelatedLocalIdentfier = "SELECT COUNT (*) FROM domain_id WHERE domain = :localIdentifierDomain AND domain_id = :localIdentifier AND status = 'C'";
    private String graphWithLocalIdentfier = "SELECT COUNT (*) FROM domain_id WHERE domain = :localIdentifierDomain AND domain_id = :localIdentifier";

    private NamedParameterJdbcTemplate vaJdbcTemplate;
    private NamedParameterJdbcTemplate dodJdbcTemplate;

    private QueueSender vaPatientCorrelationQueueSender;
    private QueueSender dodPatientCorrelationQueueSender;


    @Resource
    public void setVaJdbcTemplate( NamedParameterJdbcTemplate vaJdbcTemplate )
    {
        this.vaJdbcTemplate = vaJdbcTemplate;
    }


    @Resource
    public void setDodJdbcTemplate( NamedParameterJdbcTemplate dodJdbcTemplate )
    {
        this.dodJdbcTemplate = dodJdbcTemplate;
    }


    @Resource
    public void setVaPatientCorrelationQueueSender( QueueSender vaPatientCorrelationQueueSender )
    {
        this.vaPatientCorrelationQueueSender = vaPatientCorrelationQueueSender;
    }


    @Resource
    public void setDodPatientCorrelationQueueSender( QueueSender dodPatientCorrelationQueueSender )
    {
        this.dodPatientCorrelationQueueSender = dodPatientCorrelationQueueSender;
    }


    /***
     * HandleMessage processes Patient graph XML messages from the ErrorQueue. Graph messages exist in ErrorQueue as a consequence of exceptions 
     * during Patient Correlation.   
     * @param decodedXmlMessage is the XML part of the message extracted from ErrorQueue
     * @throws PatientBuilderException when we cannot build a Patient Graph from the message in ErrorQueue  
     */
    public void handleMessage( String decodedXmlMessage )
        throws PatientBuilderException
    {
        PsimGraphMessageHandlerData psimGraphMessageHandlerData = buildPatient( decodedXmlMessage );
        SqlParameterSource namedParameters = new BeanPropertySqlParameterSource( psimGraphMessageHandlerData );

        if ( null != psimGraphMessageHandlerData.getLocalIdentifier() && null != psimGraphMessageHandlerData.getNationalIdentifier() )
        {
            if ( psimGraphMessageHandlerData.getLocalIdentifierDomain().contains( "HA.OSD.MIL" ) )
            {
                if ( this.dodJdbcTemplate.queryForObject( graphWithLocalAndNationalIdentifier, namedParameters, Integer.class  ) > 0)
                {
                    // Do nothing, we just removed a Dod patient with both local identifier and national identifier sharing a common correlated id
                    // dodPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
                else if ( this.dodJdbcTemplate.queryForObject( graphWithCorrelatedLocalIdentfier, namedParameters, Integer.class  ) <= 0 )
                {
                    // The local Identifier does not exist in DOMAIN_ID table, but both LID & NID exist in Graph
                    dodPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
                else
                {
                    // The LID & NID do not share a common Correlated ID
                    throw new RuntimeException( "DoD Patient with LID & ICN does not have Correlated ID between LID & ICN" );
                }
            }
            else
            {
                if ( this.vaJdbcTemplate.queryForObject( graphWithLocalAndNationalIdentifier, namedParameters, Integer.class  ) > 0 )
                {
                    // Do nothing, we just removed a VA patient with both local identifier and national identifier sharing a common correlated id
                    // vaPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
                else if ( this.vaJdbcTemplate.queryForObject( graphWithCorrelatedLocalIdentfier, namedParameters, Integer.class  ) <= 0 )
                {
                    // The local Identifier does not exist, but both LID & NID exist in Graph
                    vaPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
                else
                {
                    // The local Identifier does not share a Correlated Id with its corresponding National Identifier
                    throw new RuntimeException( "VA Patient with LID & ICN does not have Correlated ID between LID & ICN" );
                }
            }
        }
        else if ( null != psimGraphMessageHandlerData.getLocalIdentifier() && null == psimGraphMessageHandlerData.getNationalIdentifier() )
        {
            if ( psimGraphMessageHandlerData.getLocalIdentifierDomain().contains( "HA.OSD.MIL" ) )
            {
                if ( this.dodJdbcTemplate.queryForObject( graphWithCorrelatedLocalIdentfier, namedParameters, Integer.class  ) > 0 )
                {
                    // Do nothing, we just removed a Dod patient with a correlated local identifier
                }
                else if ( this.dodJdbcTemplate.queryForObject( graphWithLocalIdentfier, namedParameters, Integer.class  ) <= 0
                                && psimGraphMessageHandlerData.getLocalIdentifierDomain().contains( "200HD" ) )
                {
                    // Local Identifier is not present in domain id table, keep in ErrorQueue for DoD patients
                    throw new RuntimeException( "DoD Patient with only LID does not have Correlated ID for LID" );
                }
                else
                {
                    // Local Identifier is present in DOMAIN_ID table, but not correlated
                    dodPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
            }
            else
            {
                if ( this.vaJdbcTemplate.queryForObject( graphWithCorrelatedLocalIdentfier, namedParameters, Integer.class  ) > 0 )
                {
                    // Do nothing, we just removed a VA patient with correlated local identifier
                }
                else
                {
                    // Patient with only Local Identifier which is not present in DOMAIN table or is present in table and not correlated  
                    vaPatientCorrelationQueueSender.sendMessage( decodedXmlMessage.toString() );
                }
            }
        }
        else
        {
            throw new RuntimeException( "Patient has only ICN" );
        }
    }


    private PsimGraphMessageHandlerData buildPatient( String decodedXmlMessage )
        throws PatientBuilderException
    {
        Patient patient = XMLPatientBuilder.buildPaitient( decodedXmlMessage );

        PsimGraphMessageHandlerData psimGraphMessageHandlerData = new PsimGraphMessageHandlerData();

        PatientIdentifier patientLocalIdentifier = patient.getFirstIdentifier( Patient.TYPEID_LOCAL );
        PatientIdentifier patientNationalIdentifier = patient.getFirstIdentifier( Patient.TYPEID_NATIONAL );

        psimGraphMessageHandlerData.setLocalIdentifier( patientLocalIdentifier.getId() );
        psimGraphMessageHandlerData.setLocalIdentifierDomain( patientLocalIdentifier.getDomain() );

        if ( null != patientNationalIdentifier )
        {
            psimGraphMessageHandlerData.setNationalIdentifier( patientNationalIdentifier.getId() );
            psimGraphMessageHandlerData.setNationalIdentifierDomain( patientNationalIdentifier.getDomain() );
        }

        return psimGraphMessageHandlerData;
    }
}
