

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.junit.runners.SuiteAwareSpringRunner;
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.HAExerciseJournalBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPatientEnteredExerciseJournalEntryBuilderFactory;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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

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


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndPatientEnteredExerciseJournalEntryTest
    extends
        AbstractHealthAdapterEndToEndTest
{

    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testExerciseJournalDetailsCRUD( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        ///CREATE
        String createRequestXml = createHACreateXml( uniquePatientIdentity, "PatientEnteredExerciseJournalEntry", HA_CREATE_TEMPLATE_ID, null, "CREATE" );
        Document createRequest = DocumentHelper.parseText( createRequestXml );
        String hexBinaryAttachmentName = createRequest.selectSingleNode("//hexBinaryAttachment").getParent().elementText("name");
        String base64BinaryAttachmentName = createRequest.selectSingleNode("//base64BinaryAttachment").getParent().elementText("name");
        requestProcessor.setValidateReadResponseXML( true );
        createXmlRequestId = new UniqueIdentifier().toString();
        Document createResponse = requestProcessor.createClinicalData( createRequestXml, HA_CREATE_TEMPLATE_ID, createXmlRequestId );
        assertNotNull( createResponse );
        List<Element> recordIdentifierList = createResponse.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        assertTrue( recordIdentifierList.size() == 1 );
        recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();
        createRequest = null;
        createResponse = null;

        /// DETAIL READ
        Map<String, String> otherQueryParameters = new HashMap<String, String>();
        otherQueryParameters.put( "attachmentName", hexBinaryAttachmentName );
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();
        String detailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( "PatientEnteredExerciseJournalEntry", recordIdentifier, otherQueryParameters );
        Document readDetailsWithHex = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, detailFilterXml,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER, "//genericJournalEntryDetails/patient", 1 );
        List<Element> dataList = readDetailsWithHex.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        List<Element> hexAttachmentList = readDetailsWithHex.selectNodes("//hexBinaryAttachment");
        assertTrue( hexAttachmentList.size()==1);
        readDetailsWithHex=null;
        
        otherQueryParameters.put( "attachmentName", base64BinaryAttachmentName );
        detailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( "PatientEnteredExerciseJournalEntry", recordIdentifier, otherQueryParameters );
        Document readDetailsWithBase64 = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, detailFilterXml,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER, "//genericJournalEntryDetails/patient", 1 );
        dataList = readDetailsWithBase64.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        List<Element> base64AttachmentList = readDetailsWithBase64.selectNodes("//base64BinaryAttachment");
        assertTrue( base64AttachmentList.size()==1);
        readDetailsWithBase64=null;
        
        /// READ
        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "PatientEnteredExerciseJournalEntry" );
        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredExerciseJournalEntry", FILTER_ID, null, null );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, PATIENT_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH, 1 );
        filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredExerciseJournalEntry", FILTER_ID, START_DATE, START_DATE );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, PATIENT_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH, 1 );

        /// UPDATE  Exercise Journal with different attachment
        String updateRequestXml = createHACreateXml( uniquePatientIdentity, "PatientEnteredExerciseJournalEntry", HA_UPDATE_TEMPLATE_ID, recordIdentifier, "UPDATE" );
        Document updateResponse = updateAndAssertDomainData( HA_UPDATE_TEMPLATE_ID, updateRequestXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID" );
        assertNotNull( updateResponse );

        /*Update ExerciseJournal with identical attachment*/
        Document createDocument = DocumentHelper.parseText( createRequestXml );
        Node binAttNode = createDocument
                        .selectSingleNode( "/clinicaldata:ClinicalData/patient/patientJournalEntries/patientjournaling:patientEnteredExerciseJournalEntry/genericJournalEntryDetails/binaryAttachments" );
        Document updateDocument = DocumentHelper.parseText( updateRequestXml );
        updateDocument.selectSingleNode( "/clinicaldata:ClinicalData/patient/patientJournalEntries/patientjournaling:patientEnteredExerciseJournalEntry/genericJournalEntryDetails/binaryAttachments" )
                        .detach();
        updateDocument.getRootElement().element( "patient" ).element( "patientJournalEntries" ).element( "patientEnteredExerciseJournalEntry" ).element( "genericJournalEntryDetails" )
                        .add( binAttNode.detach() );

        updateRequestXml = updateDocument.asXML();

        updateResponse = updateAndAssertDomainData( HA_UPDATE_TEMPLATE_ID, updateRequestXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID" );
        assertNotNull( updateResponse );
        updateResponse = null;

        /// DETAIL READ AFTER UPDATE - no other query params
        String detailFilterAfterUpdateXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( "PatientEnteredExerciseJournalEntry", recordIdentifier, null );
        Document readResponseAfterUpdateNoName = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID,
                        detailFilterAfterUpdateXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER, "//genericJournalEntryDetails/patient", 1 );
        dataList = readResponseAfterUpdateNoName.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        List<Node> attachments = readResponseAfterUpdateNoName.selectNodes( "//binaryAttachment" );
        assertTrue( attachments.size() == 6 ); 

        /// DETAIL READ AFTER UPDATE = with specified binary attachment name
        String detailFilterAfterUpdateWithNameXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( "PatientEnteredExerciseJournalEntry", recordIdentifier, otherQueryParameters );
        Document readResponseAfterUpdateWithName = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID,
                        detailFilterAfterUpdateWithNameXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER, "//genericJournalEntryDetails/patient", 1 );
        dataList = readResponseAfterUpdateWithName.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        attachments = readResponseAfterUpdateWithName.selectNodes( "//binaryAttachment" );
        assertTrue( attachments.size() == 3 ); /// only one attachments should be returned after update when name specified

        // Logically Delete exercise journal entry
        String logicalDeleteXml = createHADeleteXml( "PatientEnteredExerciseJournalEntry", HA_DELETE_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, logicalDeleteXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID", true );

        // Physically Delete exercise journal entry
        String physicalDeleteXml = createHADeleteXml( "PatientEnteredExerciseJournalEntry", HA_DELETE_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, physicalDeleteXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID", false );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateReadUpdateAndDeletePatientEnteredExerciseJournalEntry( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        // create request with a 'null' patientId
        String createRequestXml = createHACreateXml( "", "PatientEnteredExerciseJournalEntry", HA_CREATE_TEMPLATE_ID, null, "CREATE" );
        requestProcessor.setValidateReadResponseXML( true );
        createXmlRequestId = new UniqueIdentifier().toString();
        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestXml, HA_CREATE_TEMPLATE_ID, createXmlRequestId );
        assertNotNull( clinicalDataDocument );
        Element exceptionElement = ( Element )clinicalDataDocument.selectSingleNode( FATAL_ERRORS_EXCEPTIONS_XPATH );
        assertNotNull( exceptionElement );
        assertTrue( exceptionElement.getText().endsWith( "SchemaValidationException" ) );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "PatientEnteredExerciseJournalEntry", HA_CREATE_TEMPLATE_ID, null, "CREATE" );

        clinicalDataDocument = createAndAssertDomainData( HA_CREATE_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();

        // Read back the created record
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "PatientEnteredExerciseJournalEntry" );

        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredExerciseJournalEntry", FILTER_ID, null, null );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, PATIENT_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH, 1 );
        filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredExerciseJournalEntry", FILTER_ID, START_DATE, START_DATE );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, PATIENT_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH, 1 );

        // update request with a 'null' patientId
        String updateRequestXml = createHACreateXml( " ", "PatientEnteredExerciseJournalEntry", HA_UPDATE_TEMPLATE_ID, recordIdentifier, "UPDATE" );

        String requestId = new UniqueIdentifier().toString();
        Document clinicalDataDocumentUpdate = requestProcessor.updateClinicalData( updateRequestXml, HA_UPDATE_TEMPLATE_ID, requestId );
        assertNotNull( clinicalDataDocumentUpdate );
        exceptionElement = ( Element )clinicalDataDocumentUpdate.selectSingleNode( FATAL_ERRORS_EXCEPTIONS_XPATH );
        assertNotNull( exceptionElement );
        assertTrue( exceptionElement.getText().endsWith( "SchemaValidationException" ) );

        // Update exercise journal entry
        updateRequestXml = createHACreateXml( uniquePatientIdentity, "PatientEnteredExerciseJournalEntry", HA_UPDATE_TEMPLATE_ID, recordIdentifier, "UPDATE" );

        clinicalDataDocumentUpdate = updateAndAssertDomainData( HA_UPDATE_TEMPLATE_ID, updateRequestXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID" );
        assertNotNull( clinicalDataDocumentUpdate );

        /*Start-Delete after use - Test Code Only*/
        //filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredExerciseJournalEntry", FILTER_ID, null, null );
        //readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, filterXml, FILTER_ID, PATIENT_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH, 1 );
        /*End - Delete after use*/

        // Logically Delete exercise journal entry
        String logicalDeleteXml = createHADeleteXml( "PatientEnteredExerciseJournalEntry", HA_DELETE_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, logicalDeleteXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID", true );

        // Physically Delete exercise journal entry
        String physicalDeleteXml = createHADeleteXml( "PatientEnteredExerciseJournalEntry", HA_DELETE_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, physicalDeleteXml, "EXERCISE_JOURNAL", "EXERCISE_JOURNAL_ID", false );
    }


    private void doDelete( String patientId )
    {
        hdrJdbcTemplate.update( "DELETE FROM EXERCISE_JOURNAL WHERE PATIENT_IDENTITY = '" + patientId + "'" );
    }


    private String createHACreateXml( String patientIdentifier, String entryPoint, String templateId, String recordIdentifier, String activityDurVal )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.PatientEnteredExerciseJournalEntry );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPatientEnteredExerciseJournalEntryBuilderFactory factory = new HAPatientEnteredExerciseJournalEntryBuilderFactory();
        factory.setExerciseJournalBuilder( new HAExerciseJournalBuilder( recordIdentifier, activityDurVal ) );
        domainEntryPointsWrappersMap.put( "PatientEnteredExerciseJournalEntry", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

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

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

        return vdmClinicalDataInsert.asXML();
    }


    protected String createHADeleteXml( String entryPoint, String templateId, String recordIdentifierIdentity, String recordStatus )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.PatientEnteredExerciseJournalEntry );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPatientEnteredExerciseJournalEntryBuilderFactory factory = new HAPatientEnteredExerciseJournalEntryBuilderFactory();
        factory.setExerciseJournalBuilder( new HAExerciseJournalBuilder() );

        domainEntryPointsWrappersMap.put( "PatientEnteredExerciseJournalEntry", 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();
    }
}
