

package gov.va.med.cds.integration.vim.ha;


import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;
import gov.va.med.cds.testharness.vhim400.builders.BaseDatatypesBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDataBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDomainBuilderFactoryInterface;
import gov.va.med.cds.testharness.vhim400.builders.FilterBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainReassessmentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainReassessmentBuilderFactory;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.Test;


public class EndToEndPainReassessmentTest
    extends
        AbstractHealthAdapterEndToEndTest
{
    private static final Log LOGGER = LogFactory.getLog( EndToEndPainReassessmentTest.class );
    private String PATIENT_DOMAINENTRYPOINT_XPATH = "/clinicaldata:ClinicalData/patients/patient/painReassessments/painReassessment";


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCRUDPainReassessment( )
        throws Exception
    {
        hdrJdbcTemplate.update( "delete from pain_reassessment where patient_identity like '" + uniquePatientIdentity + "%'" );

        String createRequestXml = generatePainReassessmentXml( uniquePatientIdentity, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null );

        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );

        // Check for record identifiers in the response for the newly created record(s)
        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        String recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();

        // Update pain reassessment 
        String updateRequestXml = generatePainReassessmentXml( uniquePatientIdentity, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        recordIdentifier );
        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml );

        assertNotNull( clinicalDataDocumentUpdate );

        String deleteXml = generatePainReassessmentDeleteXml( "PainReassessment", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                        recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );

        deleteXml = generatePainReassessmentDeleteXml( "PainReassessment", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, "0" );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );
    }
    
    
    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCRUDPainReassessment_RatingError( )
        throws Exception
    {
        hdrJdbcTemplate.update( "delete from pain_reassessment where patient_identity like '" + uniquePatientIdentity + "%'" );
        requestProcessor.setValidateReadResponseXML( true );
        createXmlRequestId = new UniqueIdentifier().toString();

        // Create a request that includes a null <rating/> element
        String createRequestNullRating = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <templateId>HealthAdapterCreate1</templateId> <patient> <painReassessments> <painReassessment> <patient> <identifier> <identity>Identity</identity> <assigningFacility>200DOD</assigningFacility> <assigningAuthority>USDOD</assigningAuthority> </identifier> <name> <prefix>Prefix</prefix> <given>Given</given> <middle>MiddleName</middle> <family>FamilyName</family> <suffix>Suffix</suffix> <title>Title</title> </name> </patient> <assessmentDate> <literal>19691231170000-0700</literal> </assessmentDate> <reassessmentDate> <literal>19691231170000-0700</literal> </reassessmentDate> <avgPainLevel> <rating/> <question/> </avgPainLevel> <dataEnterer>dataEnterer</dataEnterer> <allowAccessByClinicalStaff>true</allowAccessByClinicalStaff> </painReassessment> </painReassessments> </patient> </clinicaldata:ClinicalData>";
        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestNullRating, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createXmlRequestId );

        // This should NOT throw a validation error
        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        assertTrue( recordIdentifierList.size() > 0 );
        
        // Create a request that includes an alpha char in a <rating> field
        String createRequestXmlAlphaChar = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <templateId>HealthAdapterCreate1</templateId> <patient> <painReassessments> <painReassessment> <patient> <identifier> <identity>Identity</identity> <assigningFacility>200DOD</assigningFacility> <assigningAuthority>USDOD</assigningAuthority> </identifier> <name> <prefix>Prefix</prefix> <given>Given</given> <middle>MiddleName</middle> <family>FamilyName</family> <suffix>Suffix</suffix> <title>Title</title> </name> </patient> <assessmentDate> <literal>19691231170000-0700</literal> </assessmentDate> <reassessmentDate> <literal>19691231170000-0700</literal> </reassessmentDate> <avgPainLevel> <rating>Rating</rating> <question>Question</question> </avgPainLevel> <dataEnterer>dataEnterer</dataEnterer> <allowAccessByClinicalStaff>true</allowAccessByClinicalStaff> </painReassessment> </painReassessments> </patient> </clinicaldata:ClinicalData>";
        clinicalDataDocument = requestProcessor.createClinicalData( createRequestXmlAlphaChar, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createXmlRequestId );
        
        // Check for schema validation error
        List<Element> fatalErrorList = clinicalDataDocument.selectNodes( FATAL_ERRORS_EXCEPTIONS_XPATH );
        assertTrue( fatalErrorList.size() > 0 );
    }

    
    @Test
    @Suite( groups = { "deprecatedtest" } )
    @SuppressWarnings( "unchecked" )
    public void testReadPainReassessment( )
        throws Exception
    {
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "PainReassessment" );
        entryPointFilterMap.put( FilterBuilder.QUERY_TIMEOUT_SECONDS, QUERY_TIMOUT_SECONDS_MAX );

        String filterXml = createHAFilter( TEST_READ_PATIENTIDENTITY_HDR, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR,
                        "PainReassessment", TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, null, null );

        if ( LOGGER.isDebugEnabled() )
        {
            LOGGER.debug( "filterXml - " + filterXml );
        }

        Document clinicalDataDocument = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID,
                        filterXml, TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER );

        List<Element> patientsList = clinicalDataDocument.selectNodes( PATIENT_IDENTITY_XPATH );
        assertTrue( patientsList.size() > 0 );
    }
    

    @Test
    @Suite( groups = { "deprecatedtest" } )
    @SuppressWarnings( "unchecked" )
    public void testReadPainReassessmentWithDates( )
        throws Exception
    {
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "PainReassessment" );
        entryPointFilterMap.put( FilterBuilder.QUERY_TIMEOUT_SECONDS, QUERY_TIMOUT_SECONDS_MAX );

        String filterXml = createHAFilter( TEST_READ_PATIENTIDENTITY_HDR, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR,
                        "PainReassessment", TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, "2012-03-01",
                        "2012-03-30" );

        if ( LOGGER.isDebugEnabled() )
        {
            LOGGER.debug( "filterXml - " + filterXml );
        }

        Document clinicalDataDocument = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID,
                        filterXml, TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER );

        List<Element> patientsList = clinicalDataDocument.selectNodes( PATIENT_IDENTITY_XPATH );
        assertTrue( patientsList.size() > 0 );
    }


    private String generatePainReassessmentXml( String patientIdentifier, String templateId, String recordIdentifier )
    {

        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.PainReassessment );

        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPainReassessmentBuilderFactory factory = new HAPainReassessmentBuilderFactory();
        HAPainReassessmentBuilder painReassessmentBuilder = new HAPainReassessmentBuilder( recordIdentifier );

        factory.setPainReassessmentBuilder( painReassessmentBuilder );
        domainEntryPointsWrappersMap.put( "PainReassessment", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

        Element patient = null;
        if ( patientIdentifier == null )
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest" );
        }
        else
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest", patientIdentifier );
        }

        Document painReassessmentXml = clinicalDataBuilder.createClinicalData( templateId, 1, patient );

        return painReassessmentXml.asXML();
    }


    protected String generatePainReassessmentDeleteXml( String entryPoint, String templateId, String recordIdentifierIdentity, String recordStatus )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.PainReassessment );

        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPainReassessmentBuilderFactory factory = new HAPainReassessmentBuilderFactory();
        HAPainReassessmentBuilder painReassessmentBuilder = new HAPainReassessmentBuilder( recordIdentifier );

        factory.setPainReassessmentBuilder( painReassessmentBuilder );
        domainEntryPointsWrappersMap.put( "PainReassessment", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

        Element patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest", "200DOD", "USDOD" );
        Document clinicalDataInsert = clinicalDataBuilder.deleteClinicalData( domainEntryPointsMap.get( templateId ), templateId, patient,
                        recordIdentifierIdentity, recordStatus );

        return clinicalDataInsert.asXML();
    }


    @SuppressWarnings( "unchecked" )
    protected Document updateAndAssertDomainData( String templateId, String updateRequestXml )
        throws Exception
    {
        requestProcessor.setValidateReadResponseXML( true );

        Document clinicalDataDocument = requestProcessor.updateClinicalData( updateRequestXml, templateId, new UniqueIdentifier().toString() );
        assertNotNull( clinicalDataDocument );

        // Check for an empty error section
        List<Element> errorSections = clinicalDataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 1 );
        Element errorSection = errorSections.get( 0 );
        assertTrue( errorSection.content().size() == 0 );

        return clinicalDataDocument;
    }


    @SuppressWarnings( "unchecked" )
    protected Document deleteAndAssertDomainData( String templateId, String deleteRequestXml )
        throws Exception
    {
        requestProcessor.setValidateReadResponseXML( true );

        Document clinicalDataDocument = requestProcessor.deleteClinicalData( deleteRequestXml, templateId, new UniqueIdentifier().toString() );
        assertNotNull( clinicalDataDocument );

        // Check for error sections
        List<Element> errorSections = clinicalDataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 1 );
        Element errorSection = errorSections.get( 0 );
        assertTrue( errorSection.content().size() == 0 );

        return clinicalDataDocument;
    }
    
    
    @SuppressWarnings( "unchecked" )
    protected Document readAndAssertDomainData( Map<String, String> assigningFacilityAndPatientIdentityMap, String templateId, String filter, String filterId )
        throws Exception
    {
        Document clinicalDataDocument = super.readAndAssertDomainData( filter );

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

        return clinicalDataDocument;
    }
}
