

package gov.va.med.cds.scheduler;


import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import gov.va.med.cds.client.proxy.NetworkClientProxyInterface;
import gov.va.med.cds.exception.CensusTransformAckException;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.hapi.HL7SupportHAPI;
import gov.va.med.cds.hapi.HL7SupportInterface;
import gov.va.med.cds.hapi.HL7Utility;
import gov.va.med.cds.mediator.persistence.Hl7AuditDaoInterface;
import gov.va.med.cds.scheduler.persistence.CensusAcknowledgementResponse;
import gov.va.med.cds.scheduler.persistence.CensusCompleteWeek;
import gov.va.med.cds.scheduler.persistence.RoutingData;
import gov.va.med.cds.util.DateTimeUtil;


public class CensusAcknowledgementWork
    implements
        CensusAcknowledgementWorkInterface
{

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

    private static final String COMMIT_ACK = "CA";
    private static final String DOD_DATA = "DOD_DATA";
    private static final String VA_DATA = "VA_DATA";
    private static final String TRANSFROM_SUCCESS_STATUS = "COMPLETE";
    private static final String ERROR_MSG_DELIMITER = "\\|";
    private static final String AA_SUCCESS_MSG = "Census report has been successfully received";
    private static final String AR_EXPIRED_MSG = "Census Report segments missing or too many sent or not sent in a timely manner. Census start date: %s; Census End date: %s; Message Id: %s; Vendor Id: %s";

    private static final String HTH_CENSUS_SENDING_APP = "HTAPPL-CENSUS";

    //private String wsnHl7Support;
    private Map<String, NetworkClientProxyInterface> clientProxiesMap;
    private Map<String, Hl7AuditDaoInterface> hl7AuditDaoMap = null;


    @Override
    public void sendCensusAcknowledgement( CensusAcknowledgementResponse transformResponse )
    {
        String sendingFacility = null;
        String sentFrom = null;
        String appAck = null;

        try
        {
            if ( null != transformResponse )
            {
                sendingFacility = transformResponse.getSendingFacility();
                sentFrom = ( "200CH".equals( sendingFacility ) || "200HD".equals( sendingFacility ) ) ? DOD_DATA : VA_DATA;

                if ( transformResponse.getTransformStatus().equalsIgnoreCase( TRANSFROM_SUCCESS_STATUS ) )
                {
                    RoutingData routingData = ( RoutingData )transformResponse;
                    appAck = createAppAckNoErrors( routingData, transformResponse.getMessageControlId() );
                }
                else
                {
                    String errorMessages = ( null != transformResponse.getErrorMessage() && transformResponse.getErrorMessage().trim().length() > 0 )
                                    ? transformResponse.getErrorMessage() : null;

                    appAck = createAppAckWithErrorResponse( transformResponse, transformResponse.getMessageControlId(), errorMessages );
                }

                if ( appAck != null )
                {
                    sendAcknowledgementResponse( appAck, HTH_CENSUS_SENDING_APP, sendingFacility, sentFrom );
                }
            }
            else
            {
                logger.error( ErrorCodeEnum.CENSUS_ACKNOWLEDGEMENT_RESPONSE_IS_NULL );
                throw new CensusTransformAckException( ErrorCodeEnum.CENSUS_ACKNOWLEDGEMENT_RESPONSE_IS_NULL );
            }
        }
        catch ( Exception e )
        {
            logger.error( String.format( "Error sending acknowledement.\ncensusMasterId:\n%s", transformResponse.getCensusMasterId() ) );
            throw e;
        }
    }


    @Override
    public void sendCensusAcknowledgement( CensusCompleteWeek censusCompleteWeek, Long censusMasterId )
    {
        String sendingFacility = null;
        String sentFrom = null;
        String appAck = null;

        try
        {
            if ( null != censusCompleteWeek )
            {
                sendingFacility = censusCompleteWeek.getSendingFacility();
                sentFrom = ( "200CH".equals( sendingFacility ) || "200HD".equals( sendingFacility ) ) ? DOD_DATA : VA_DATA;

                RoutingData routingData = ( RoutingData )censusCompleteWeek;
                String errorMessage = String.format( AR_EXPIRED_MSG, DateTimeUtil.convertDate2String( censusCompleteWeek.getReportStartDt() ),
                                DateTimeUtil.convertDate2String( censusCompleteWeek.getReportEndDt() ), censusCompleteWeek.getRequestId(),
                                censusCompleteWeek.getVendorFacility() );
                appAck = createAppAckWithErrorResponse( routingData, censusCompleteWeek.getRequestId(), errorMessage );

                if ( appAck != null )
                {
                    sendAcknowledgementResponse( appAck, HTH_CENSUS_SENDING_APP, sendingFacility, sentFrom );
                }
            }
            else
            {
                logger.error( ErrorCodeEnum.CENSUS_COMPLETE_WEEK_IS_NULL );
                throw new CensusTransformAckException( ErrorCodeEnum.CENSUS_COMPLETE_WEEK_IS_NULL );
            }
        }
        catch ( Exception e )
        {
            logger.error( String.format( "Error sending acknowledement.\ncensusMasterId:\n%s", censusMasterId ) );
            throw e;
        }
    }


    private String createAppAckWithErrorResponse( RoutingData routingData, String messageControlId, String errorMessages )
    {
        return String.format( createAckResponse( routingData ).concat( "AR^%s" ), messageControlId )
                        .concat( constructErrorMessages( errorMessages ) );
    }


    private String createAppAckNoErrors( RoutingData routingData, String messageControlId )
    {
        return String.format( createAckResponse( routingData ).concat( "AA^%s^%s" ), messageControlId, AA_SUCCESS_MSG );
    }


    private String createAckResponse( RoutingData routingData )
    {
        return String.format( "MSH^~|\\&^%s^200HD~%s~DNS^%s^%s~%s~DNS^%s^^ACK^%s^P^2.4^^^AL^NE\rMSA^", routingData.getReceivingApplication(),
                        routingData.getReceivingFacility(), routingData.getSendingApplication(), routingData.getStationNumber(),
                        routingData.getSendingFacility(), createMessageDateTime(), createMessageControlId() );
    }


    private String constructErrorMessages( String errorMessages )
    {
        StringBuilder sb = new StringBuilder();

        for ( String errorMessage : errorMessages.split( ERROR_MSG_DELIMITER ) )
        {
            if ( null != errorMessage && errorMessage.trim().length() > 0 )
            {
                sb.append( String.format( "\rERR^%s", errorMessage.trim() ) );
            }
        }

        return sb.toString();
    }


    private String createMessageDateTime( )
    {
        return HL7Utility.createMessageDateTime();
    }


    private String createMessageControlId( )
    {
        return HL7Utility.createMessageControlId();
    }


    private void sendAcknowledgementResponse( String acknowledgement, String sendingApp, String sendingFacility, String sentFrom )
    {
        Hl7AuditDaoInterface hl7AuditDao = null;
        NetworkClientProxyInterface clientProxy = clientProxiesMap.get( sendingApp );

        if ( clientProxy != null )
        {
            Properties properties = new Properties();
            properties.setProperty( NetworkClientProxyInterface.PROP_DNS_NAME, sendingFacility );

            // write the acknowledgment to the HL7 Message Log
            HL7SupportInterface hl7supportACK = HL7SupportHAPI.createTranslationSupport( acknowledgement );

            if ( hl7AuditDaoMap != null )
            {
                hl7AuditDao = hl7AuditDaoMap.get( sentFrom );
                hl7AuditDao.addMessage( hl7supportACK.getMessageControlId(), acknowledgement );
            }

            // send the acknowledgment
            String acknowledgmentCommitAck = clientProxy.sendMessage( acknowledgement, properties );

            // Write an error message to the CDS Application Log if other than CA.
            HL7SupportInterface hl7SupportCA = HL7SupportHAPI.createTranslationSupport( acknowledgmentCommitAck );
            if ( !hl7SupportCA.getAcknowledgementCode().equalsIgnoreCase( COMMIT_ACK ) )
            {
                if ( logger.isErrorEnabled() )
                {
                    logger.error( String.format( "Error sending acknowledement.\nCommit Ack:\n%s", acknowledgmentCommitAck ) );
                }
                if ( logger.isDebugEnabled() )
                {
                    logger.debug( String.format( "Error sending acknowledement.\nAcknowledgement: \n%s\n\nCommit Ack:\n%s", acknowledgement,
                                    acknowledgmentCommitAck ) );
                }
            }

            // write the CA message to the HL7 Message Log
            if ( hl7AuditDao != null )
            {
                hl7AuditDao.addMessage( hl7supportACK.getMessageControlId(), acknowledgmentCommitAck );
            }
        }
    }


    public void setClientProxiesMap( Map<String, NetworkClientProxyInterface> clientProxiesMap )
    {
        this.clientProxiesMap = clientProxiesMap;
    }


    public void setHl7AuditDaoMap( Map<String, Hl7AuditDaoInterface> hl7AuditDaoMap )
    {
        this.hl7AuditDaoMap = hl7AuditDaoMap;
    }
}
