

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.HAPatienEnteredDailyEventJournalEntryBuilderFactory;
import gov.va.med.cds.testharness.vhim400.builders.PatientEnteredDailyEventBuilder;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.junit.Test;


public class EndToEndPatientEnteredDailyEventJournalTest
    extends
        AbstractHealthAdapterEndToEndTest
{
    private static final Log LOGGER = LogFactory.getLog( EndToEndPatientEnteredDailyEventJournalTest.class );

    private String PATIENTIDENTITY_HDR = "DailyEventPatient";


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testDailyEventJournalDetailsCRUD( )
        throws Exception
    {
    	hdrJdbcTemplate.update( "delete from daily_event_journal where patient_identity like '" + PATIENTIDENTITY_HDR + "%'" );
    	PATIENTIDENTITY_HDR= PATIENTIDENTITY_HDR + ( ( int )( Math.random() * 10000000 ) );

        ///CREATE
        String createRequestXml = generatePatientEnteredDailyEventJournalXml( PATIENTIDENTITY_HDR, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, null );
        Document createRequest = DocumentHelper.parseText(createRequestXml);
      
        String hexBinaryAttachmentName = createRequest.selectSingleNode("//hexBinaryAttachment").getParent().elementText("name");
        String base64BinaryAttachmentName = createRequest.selectSingleNode("//base64BinaryAttachment").getParent().elementText("name");
        
        Document createResponse = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );
        List<Element> recordIdentifierList = createResponse.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        String recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();
        createRequest=null;
        createResponse = null;
        
        /// READ DETAIL requesting hex attachment
        Map<String, String> otherQueryParameters = new HashMap<String, String>();
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String,String>(); 
        otherQueryParameters.put("attachmentName", hexBinaryAttachmentName);
        String beforeUpdateDetailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter("PatientEnteredDailyEventJournalEntry", recordIdentifier, otherQueryParameters);
        Document readDetailWithHex = readAndAssertDomainData( assigningAuthorityAndFacilityMap,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, beforeUpdateDetailFilterXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER,
                        "//genericJournalEntryDetails/patient", 1 );
        List<Object> dataList = readDetailWithHex.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        List<Object> hexAttachmentList = readDetailWithHex.selectNodes("//hexBinaryAttachment");
        assertTrue( hexAttachmentList.size()==1);
        readDetailWithHex=null;
        
        /// READ DETAIL requesting base64 attachment
        otherQueryParameters.put("attachmentName", base64BinaryAttachmentName);
        beforeUpdateDetailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter("PatientEnteredDailyEventJournalEntry", recordIdentifier, otherQueryParameters);
        Document readDetailWithBase64 = readAndAssertDomainData( assigningAuthorityAndFacilityMap,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, beforeUpdateDetailFilterXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER,
                        "//genericJournalEntryDetails/patient", 1 );
        dataList = readDetailWithBase64.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );
        List<Object> base64AttachmentList = readDetailWithBase64.selectNodes("//base64BinaryAttachment");
        assertTrue( base64AttachmentList.size()==1);
        readDetailWithBase64=null;
        
        
        // UPDATE
        String updateRequestXml = generatePatientEnteredDailyEventJournalXml( PATIENTIDENTITY_HDR, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, recordIdentifier, null );
        Document updateRequest = DocumentHelper.parseText(updateRequestXml);
        String attachmentName2 = updateRequest.selectSingleNode("//binaryAttachments/binaryAttachment/name").getText();
        otherQueryParameters.put("attachmentName", attachmentName2);
        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml );
        assertNotNull( clinicalDataDocumentUpdate );

        /// READ DETAIL after update and with update attachment name
        String afterUpdateDetailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter("PatientEnteredDailyEventJournalEntry", recordIdentifier, otherQueryParameters);
        Document afterUpdateReadResponseWithName = readAndAssertDomainData( assigningAuthorityAndFacilityMap,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, afterUpdateDetailFilterXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER,
                        "//genericJournalEntryDetails/patient", 1 );
        dataList = afterUpdateReadResponseWithName.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 ); 
        List<Node> attachments = afterUpdateReadResponseWithName.selectNodes("//binaryAttachment");
        assertTrue( attachments.size()==2);          

        
        /// READ DETAIL after update and without attachment name
        String afterUpdateDetailFilterNoNameXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter("PatientEnteredDailyEventJournalEntry", recordIdentifier, null);
        Document afterUpdateReadResponseWithoutName = readAndAssertDomainData( assigningAuthorityAndFacilityMap,
                        TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID, afterUpdateDetailFilterNoNameXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER,
                        "//genericJournalEntryDetails/patient", 1 );
        dataList = afterUpdateReadResponseWithoutName.selectNodes( "//patients/patient/patientJournalEntries" );
        assertTrue( dataList.size() > 0 );   
        attachments = afterUpdateReadResponseWithoutName.selectNodes("//binaryAttachment");
        assertTrue( attachments.size()==4);        
        
        
        String deleteXml = generatePatientEnteredDailyEventJournalEntryDeleteXml( "PatientEnteredDailyEventJournalEntry", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier,
                        LOGICAL_DELETE_RECORD_STATUS );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );

        deleteXml = generatePatientEnteredDailyEventJournalEntryDeleteXml( "PatientEnteredDailyEventJournalEntry", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, "0" );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );

    }

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

        PATIENTIDENTITY_HDR = PATIENTIDENTITY_HDR + ( ( int )( Math.random() * 10000000 ) );

        String createRequestXml = generatePatientEnteredDailyEventJournalXml( PATIENTIDENTITY_HDR, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, 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 exercise journal entry
        String updateRequestXml = generatePatientEnteredDailyEventJournalXml( PATIENTIDENTITY_HDR, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, recordIdentifier, null );
        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml );
        assertNotNull( clinicalDataDocumentUpdate );

        String deleteXml = generatePatientEnteredDailyEventJournalEntryDeleteXml( "PatientEnteredDailyEventJournalEntry", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier,
                        LOGICAL_DELETE_RECORD_STATUS );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );

        deleteXml = generatePatientEnteredDailyEventJournalEntryDeleteXml( "PatientEnteredDailyEventJournalEntry", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, "0" );

        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml );

    }


    @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 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 createAndAssertDomainData( String templateId, String updateRequestXml )
        throws Exception
    {
        requestProcessor.setValidateReadResponseXML( true );
        createXmlRequestId = new UniqueIdentifier().toString();
        
        Document clinicalDataDocument = requestProcessor.createClinicalData( 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 );

        // Check for recordIdentifier elements
        //List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( CREATED_JOURNAL_ENTRY_RECORD_IDENTIFIER_XPATH );
        //assertTrue( recordIdentifierList.size() > 0 );

        return clinicalDataDocument;
    }


    private String generatePatientEnteredDailyEventJournalXml( String patientIdentifier, String templateId, String recordIdentifier, String attachmentName )
    {

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

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

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPatienEnteredDailyEventJournalEntryBuilderFactory factory = new HAPatienEnteredDailyEventJournalEntryBuilderFactory();
        PatientEnteredDailyEventBuilder patientEnteredDailyEventBuilder = new PatientEnteredDailyEventBuilder();
        patientEnteredDailyEventBuilder.setRecordIdentifer( recordIdentifier );
        patientEnteredDailyEventBuilder.setAttachmentName( attachmentName );
        
        factory.setDailyEventJournalEntryBuilder( patientEnteredDailyEventBuilder );
        domainEntryPointsWrappersMap.put( "PatientEnteredDailyEventJournalEntry", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

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

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

        return patientEnteredDailyEventJournalXml.asXML();
    }


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

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPatienEnteredDailyEventJournalEntryBuilderFactory factory = new HAPatienEnteredDailyEventJournalEntryBuilderFactory();
        factory.setDailyEventJournalEntryBuilder( new PatientEnteredDailyEventBuilder() );

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


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

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

        String filterXml = createMHAFilter( TEST_READ_PATIENTIDENTITY_HDR, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredDailyEventJournalEntry",
                        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 );

        prettyPrint(clinicalDataDocument,"Example-DailyEventJournal-Read-Response-with-attachment-meta-data");
        
        List<Element> patientsList = clinicalDataDocument.selectNodes( PATIENT_IDENTITY_XPATH );
        assertTrue( patientsList.size() > 0 );
    }


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

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

        String filterXml = createMHAFilter( TEST_READ_PATIENTIDENTITY_HDR, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PatientEnteredDailyEventJournalEntry",
                        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 );
    }


    @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_ENTEREDJOURNAL_DOMAINENTRYPOINT_XPATH );
        assertTrue( domainElements.size() > 0 );

        return clinicalDataDocument;
    }


    protected String createMHAFilter( String patientIdentifier, String assigningAuthority, String assigningFacility, String entryPoint, String filterId, String startDate, String endDate )
    {
        Document filterDocument = FilterBuilder.buildEmptyFilterDocument();

        Element element = filterDocument.getRootElement();

        element.add( FilterBuilder.createFilterId( "filterId", filterId ) );
        element.add( FilterBuilder.createClientName( "clientName", "testClientName" ) );
        element.add( FilterBuilder.createClientRequestInitiationTime( "clientRequestInitiationTime", DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ) ) );
        element.add( FilterBuilder.createPatientWithEdipi( "patients", patientIdentifier, null, assigningAuthority, assigningFacility ) );
        element.add( FilterBuilder.createMHAEntryFilterWithAdditionalParameters( "entryPointFilter", entryPoint, startDate, endDate, "ID_1" ) );
        element.addAttribute( "vhimVersion", "Vhim_4_00" );

        return element.asXML();
    }

}
