

package gov.va.med.cds.integration.vhim400;


import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.integration.AbstractEndToEndTest;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.request.RequestProcessorInterface;
import gov.va.med.cds.request.TemplateRequestProcessor;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;
import gov.va.med.cds.testharness.vhim400.builders.FilterBuilder;
import gov.va.med.cds.testharness.xml.Assert;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndReadReleaseOfInformationTest
    extends
        AbstractEndToEndTest
{
    private static final String PATIENT_IDENTITY_VISTA = "1";
    private static final String PATIENT_IDENTITY_VISTA_FAILING1 = "999999";
    private static final String PATIENT_IDENTITY_VISTA_FAILING2 = "patient_identity_1";
    private static final String ASSIGNING_FACILITY_VISTA_580 = "580";
    private static final String ASSIGNING_FACILITY_VISTA_578 = "578";
    private static final String ASSIGNINGFACILITY_FAILURE_1 = "503";
    private static final String ASSIGNINGFACILITY_FAILURE_2 = "504";
    private static final String ASSIGNING_AUTHORITY_VISTA = "USVHA";

    private static final String XPATH_RELEASEOFINFORMATION = "/releaseofinformationdata:ReleaseOfInformationData/patients/patient/releasesOfInformation/releaseOfInformation";
    private static final String XPATH_ERRORSECTION = "//errorSection";
    private static final String XPATH_ERRORSECTION_WARNING = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/warnings/warning";
    private static final String XPATH_ERRORSECTION_WARNING_ERRORCODE = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/warnings/warning/errorCode";
    @SuppressWarnings( "unused" )
    private static final String XPATH_ERRORSECTION_ERROR = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/errors/error";
    private static final String XPATH_ERRORSECTION_ERROR_ERRORCODE = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/errors/error/errorCode";
    private static final String XPATH_ERRORSECTION_FATALERROR = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/fatalErrors/fatalError";
    private static final String XPATH_ERRORSECTION_FATALERROR_ERRORCODE = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/fatalErrors/fatalError/errorCode";
    @SuppressWarnings( "unused" )
    private static final String XPATH_ERRORSECTION_WARNING_DISPLAYMSG = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/warnings/warning/displayMessage";
    private static final String XPATH_ERRORSECTION_FATALERROR_DISPLAYMSG = "/releaseofinformationdata:ReleaseOfInformationData/errorSection/fatalErrors/fatalError/displayMessage";

    @Resource
    private RequestProcessorInterface rpcRequestProcessor = null;
    protected TemplateRequestProcessor templateRequestProcessor;


    @Before
    @Suite( groups = { "deprecatedtest" } )
    public void beforeEndToEndReadVrmTestClassSetUp( )
        throws Exception
    {
        templateRequestProcessor = ( TemplateRequestProcessor )getRpcRequestProcessor();
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformationNoDates_SingleSite( )
        throws Exception
    {
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient521 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[][] patientIdentifiers = { vistaPatient521 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, null, null, clientRequestInitiationTime ).asXML();

        Document dataDocument = readAndAssertDomainData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId, filterXml, resolvedPatients );

        List<Element> elementList = dataDocument.selectNodes( XPATH_RELEASEOFINFORMATION );
        assertTrue( elementList.size() == 2 );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformationWithDates_SingleSite( )
        throws Exception
    {
        String startDate = "2014-03-01"; 
        String endDate = "2015-03-01"; 
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient521 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[][] patientIdentifiers = { vistaPatient521 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();
        
        Document dataDocument = readAndAssertDomainData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId, filterXml, resolvedPatients );

        List<Element> elementList = dataDocument.selectNodes( XPATH_RELEASEOFINFORMATION );
        assertTrue( elementList.size() == 1 );
    }

    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "timeouttest" } )
    /* this test is failing only on continuous, should be fixed*/
    public void testVistaReleaseOfInformationWithDates_MultiSiteTimeout( )
        throws Exception
    {
        String TIMOUT_SECONDS = "1";

        String startDate = "2003-01-01";
        String endDate = "2015-12-30";
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient580 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_580, PATIENT_IDENTITY_VISTA };
        String[] vistaPatient578 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[][] patientIdentifiers = { vistaPatient580, vistaPatient578 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_TIMEOUT_SECONDS, TIMOUT_SECONDS );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();

        Document dataDocument = templateRequestProcessor.readClinicalData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID, filterXml,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId );

        List<Element> elementList = dataDocument.selectNodes( XPATH_ERRORSECTION_ERROR_ERRORCODE );
        if ( elementList != null && elementList.size() > 0 )
        {
            assertTrue( elementList.get( 0 ).getText().equals( TIMOUT_ERROR_CODE ) );            
        }
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformationStartDateNoEndDate_SingleSite( )
        throws Exception
    {
        String startDate = "2003-01-01";
        String endDate = null;
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient521 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[][] patientIdentifiers = { vistaPatient521 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();

        Document dataDocument = readAndAssertDomainData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId, filterXml, resolvedPatients );

        List<Element> elementList = dataDocument.selectNodes( XPATH_RELEASEOFINFORMATION );
        assertTrue( elementList.size() == 2 );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformationEndDateNoStartDate_SingleSite( )
        throws Exception
    {
        String startDate = null;
        String endDate = "2015-12-01";
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient521 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[][] patientIdentifiers = { vistaPatient521 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();

        Document dataDocument = readAndAssertDomainData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId, filterXml, resolvedPatients );

        List<Element> elementList = dataDocument.selectNodes( XPATH_RELEASEOFINFORMATION );
        assertTrue( elementList.size() == 2 );
    }

    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformationPartialReadOneFailure_MultiSite( )
        throws Exception
    {
        String startDate = "2003-01-01";
        String endDate = "2015-12-30";
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        // build resolved patients
        String[] vistaPatient580 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA_578, PATIENT_IDENTITY_VISTA };
        String[] vistaPatient503 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNINGFACILITY_FAILURE_1, PATIENT_IDENTITY_VISTA_FAILING1 };
        String[][] patientIdentifiers = { vistaPatient580, vistaPatient503 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();

        templateRequestProcessor.setValidateReadResponseXML( false );
        Document dataDocument = templateRequestProcessor.readClinicalData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID, filterXml,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId );
        assertNotNull( dataDocument );
       

        // Check for error sections
        List<Element> errorSections = dataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 1 );

        //make sure we reported one  READ_REQUEST_DATA_SOURCE_FAILURE successfully as a warning
        List<Node> warningNodes = dataDocument.selectNodes( XPATH_ERRORSECTION_WARNING );
        Assert.assertTrue( warningNodes.size() == 1 );

        Node errorCodeNode = dataDocument.selectSingleNode( XPATH_ERRORSECTION_WARNING_ERRORCODE );
        Assert.assertTrue( errorCodeNode.getText().contains( READ_REQUEST_DATA_SOURCE_FAILURE ) );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testVistaReleaseOfInformation_AllSitesFailure( )
        throws Exception
    {
        String startDate = "2002-01-01";
        String endDate = "2011-06-01";
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        String requestId = TemplateIdHelper.getUniqueIdentifier(); 

        // build resolved patients
        String[] vistaPatient503 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNINGFACILITY_FAILURE_1, PATIENT_IDENTITY_VISTA_FAILING1 };
        String[] vistaPatient504 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNINGFACILITY_FAILURE_2, PATIENT_IDENTITY_VISTA_FAILING2 };
        String[][] patientIdentifiers = { vistaPatient503, vistaPatient504 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        // build entry point 
        Map<String, String> entryPointFilterMapAppts = new HashMap<String, String>();
        entryPointFilterMapAppts.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "ReleaseOfInformation" );
        entryPointFilterMapAppts.put( FilterBuilder.QUERY_NAME_KEY, "ReleaseOfInformation-Standardized" );
        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMapAppts );

        // build filter
        String filterXml = FilterBuilder.buildAppointmentsFilterElementWithResolvedIdentfiers( TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER,
                        entryPointFilterMaps, resolvedPatients, startDate, endDate, clientRequestInitiationTime ).asXML();

        templateRequestProcessor.setValidateReadResponseXML( false );
        Document dataDocument = templateRequestProcessor.readClinicalData( TemplateIdHelper.RELEASEOFINFORMATION_READ_TEMPLATE_ID, filterXml,
                        TemplateIdHelper.RELEASEOFINFORMATION_SINGLE_PATIENT_FILTER, requestId );
        assertNotNull( dataDocument );

        // Check for error sections
        List<Element> errorSections = dataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 1 );

        // make sure we reported error message as a fatalError
        List<Node> warningNodes = dataDocument.selectNodes( XPATH_ERRORSECTION_FATALERROR );
        Assert.assertTrue( warningNodes.size() == 1 );

        // make sure we reported one READ_REQUEST_ALL_DATA_SOURCES_FAILED successfully as a fatalError        
        Node errorCodeNode = dataDocument.selectSingleNode( XPATH_ERRORSECTION_FATALERROR_ERRORCODE );
        Assert.assertTrue( errorCodeNode.getText().contains( READ_REQUEST_ALL_DATA_SOURCES_FAILED ) );

        Node fatalErrorDisplayMsgtNode = dataDocument.selectSingleNode( XPATH_ERRORSECTION_FATALERROR_DISPLAYMSG );
        Assert.assertTrue( fatalErrorDisplayMsgtNode.getText().contains( READ_REQUEST_ALL_DATA_SOURCES_FAILED_MSG ) );
    }


    @SuppressWarnings( "unchecked" )
    protected Document readAndAssertDomainData( String templateId, String filterId, String requestId, String filterXml,
                    List<Map<String, String>> resolvedPatients )
        throws Exception
    {
        templateRequestProcessor.setValidateReadResponseXML( false );
        Document dataDocument = templateRequestProcessor.readClinicalData( templateId, filterXml, filterId, requestId );
        assertNotNull( dataDocument );

        // Check for error sections
        List<Element> errorSections = dataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 0 );

        Assert.assertXmlValidation( dataDocument.asXML(), templateId, "ReleaseOfInformationdata" );

        // Check for domain entry point elements
        List<Element> domainElements = dataDocument.selectNodes( XPATH_PATIENT );
        assertTrue( domainElements.size() > 0 );

        // Assert that the resolved identifier assigning facility values from the filter are in the result document
        List<Element> resultsResolvedIdentifiersList = dataDocument.selectNodes( CDS_XPATH_IDENTIFIERS );
        assertTrue( resultsResolvedIdentifiersList.size() == resolvedPatients.size() );
        for ( Element resultsResolvedIdentifiers : resultsResolvedIdentifiersList )
        {
            String resultsAssigningAuthority = resultsResolvedIdentifiers.selectSingleNode( XPATH_ASSIGNING_AUTHORITY_ELEMENT_NAME ).getText();
            String resultsAssigningFacility = resultsResolvedIdentifiers.selectSingleNode( XPATH_ASSIGNING_FACILITY_ELEMENT_NAME ).getText();
            String resultsPatientIdentity = resultsResolvedIdentifiers.selectSingleNode( XPATH_PATIENT_IDENTITY_ELEMENT_NAME ).getText();

            Map<String, String> assigningAuthorityFacilityAndPatientIdentityMap = null;
            for ( Map<String, String> resolvedPatientMap : resolvedPatients )
            {
                String mapAssigningAuthority = resolvedPatientMap.get( FilterBuilder.ASSIGNING_AUTHORITY_KEY );
                String mapAssigningFacility = resolvedPatientMap.get( FilterBuilder.ASSIGNING_FACILITY );
                String mapIdentity = resolvedPatientMap.get( FilterBuilder.IDENTITY );
                if ( mapAssigningAuthority != null && mapAssigningAuthority.equalsIgnoreCase( resultsAssigningAuthority )
                                && mapAssigningFacility != null && mapAssigningFacility.equalsIgnoreCase( resultsAssigningFacility )
                                && mapIdentity != null && mapIdentity.equalsIgnoreCase( resultsPatientIdentity ) )
                {
                    assigningAuthorityFacilityAndPatientIdentityMap = resolvedPatientMap;
                    break;
                }
            }

            assertNotNull( assigningAuthorityFacilityAndPatientIdentityMap );
            String mapPatientIdentity = assigningAuthorityFacilityAndPatientIdentityMap.get( FilterBuilder.IDENTITY );
            assertNotNull( mapPatientIdentity );
            assertTrue( mapPatientIdentity.equals( resultsPatientIdentity ) );
        }

        return dataDocument;
    }


    protected RequestProcessorInterface getRpcRequestProcessor( )
    {
        return rpcRequestProcessor;
    }
}
