

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

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

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


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndPainEventTest
    extends
        AbstractHealthAdapterEndToEndTest
{
    private static final String PAIN_EVENT_DOMAINENTRYPOINT_XPATH = "//painEvents";


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

        String createRequestXml = createHACreateXml( uniquePatientIdentity, "PainEvent", HA_CREATE_TEMPLATE_ID, null, null );

        Document 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", "PainEvent" );

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

        // Update pain event entry
        String updateRequestXml = createHACreateXml( uniquePatientIdentity, "PainEvent", HA_UPDATE_TEMPLATE_ID, recordIdentifier, null );
        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( HA_UPDATE_TEMPLATE_ID, updateRequestXml, "PAIN_EVENT", "PAIN_EVENT_ID" );
        assertNotNull( clinicalDataDocumentUpdate );

        // Logically Delete pain event entry
        String logicalDeleteXml = createHADeleteXml( "PainEvent", HA_DELETE_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, logicalDeleteXml, "PAIN_EVENT", "PAIN_EVENT_ID", true );

        // Physically Delete pain event entry
        String physicalDeleteXml = createHADeleteXml( "PainEvent", HA_DELETE_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, physicalDeleteXml, "PAIN_EVENT", "PAIN_EVENT_ID", false );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCRUDPainEvent_RatingError( )
        throws Exception
    {
        doDelete( 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 xsi:schemaLocation=\"Clinicaldata HealthAdapterCreate1.xsd\" xmlns:clinicaldata=\"Clinicaldata\" xmlns:patiententeredpainelements=\"PatientEnteredPainElements\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><templateId>HealthAdapterCreate1</templateId><clientName>HealthAdapter</clientName><clientRequestInitiationTime>2012-12-17T09:30:47Z</clientRequestInitiationTime><patient><painEvents><painEvent><patient><identifier><identity>" + uniquePatientIdentity + "</identity><assigningFacility>200DOD</assigningFacility><assigningAuthority>USDOD</assigningAuthority></identifier><name><prefix>Mr.</prefix><given>PRANTEST005</given><middle>KUMAR</middle><family>HDRGPRTEST05</family><suffix>Jr.</suffix><title>Tech Analyst</title></name></patient><entryDate><literal>20120626102020-0700</literal></entryDate><painType>CHRONIC</painType><treatmentUsefulness><rating></rating><question>How useful has this treatment/skill been in helping you manage your pain today?</question></treatmentUsefulness><painLevel><rating></rating><question>Rate your pain on average today</question></painLevel><painImpactOnMood><rating></rating><question>Rate how much pain has worsened your mood today</question></painImpactOnMood><painInterference><rating>4</rating><question>Rate how much pain has interfered with your activities today</question></painInterference><sleepRefreshment><rating>5</rating><question>Rate how refreshed or rested you felt after last night’s sleep</question></sleepRefreshment><depressionLevel><rating>6</rating><question>Rate how down, depressed, or hopeless you have felt today?</question></depressionLevel><impactOnFunction><rating>7</rating><question>Rate how much pain has interfered with your ability to walk and move around today </question></impactOnFunction><comments>Testing pain events by Praneeth</comments><painWorsenedBy>Eating outside food</painWorsenedBy><painImprovedBy>After vomiting</painImprovedBy><dataEnterer>HATESTGPR,TEST005</dataEnterer><painActivatedBy>Not having dinner</painActivatedBy><allowAccessByClinicalStaff>true</allowAccessByClinicalStaff><painQualityToday><painQuality>TINGLING</painQuality></painQualityToday><treatments><treatment>Sleep Management</treatment></treatments></painEvent></painEvents> </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 xsi:schemaLocation=\"Clinicaldata HealthAdapterCreate1.xsd\" xmlns:clinicaldata=\"Clinicaldata\" xmlns:patiententeredpainelements=\"PatientEnteredPainElements\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><templateId>HealthAdapterCreate1</templateId><clientName>HealthAdapter</clientName><clientRequestInitiationTime>2012-12-17T09:30:47Z</clientRequestInitiationTime><patient><painEvents><painEvent><patient><identifier><identity>" + uniquePatientIdentity + "</identity><assigningFacility>200DOD</assigningFacility><assigningAuthority>USDOD</assigningAuthority></identifier><name><prefix>Mr.</prefix><given>PRANTEST005</given><middle>KUMAR</middle><family>HDRGPRTEST05</family><suffix>Jr.</suffix><title>Tech Analyst</title></name></patient><entryDate><literal>20120626102020-0700</literal></entryDate><painType>CHRONIC</painType><treatmentUsefulness><rating>a</rating><question>How useful has this treatment/skill been in helping you manage your pain today?</question></treatmentUsefulness><painLevel><rating></rating><question>Rate your pain on average today</question></painLevel><painImpactOnMood><rating></rating><question>Rate how much pain has worsened your mood today</question></painImpactOnMood><painInterference><rating>4</rating><question>Rate how much pain has interfered with your activities today</question></painInterference><sleepRefreshment><rating>5</rating><question>Rate how refreshed or rested you felt after last night’s sleep</question></sleepRefreshment><depressionLevel><rating>6</rating><question>Rate how down, depressed, or hopeless you have felt today?</question></depressionLevel><impactOnFunction><rating>7</rating><question>Rate how much pain has interfered with your ability to walk and move around today </question></impactOnFunction><comments>Testing pain events by Praneeth</comments><painWorsenedBy>Eating outside food</painWorsenedBy><painImprovedBy>After vomiting</painImprovedBy><dataEnterer>HATESTGPR,TEST005</dataEnterer><painActivatedBy>Not having dinner</painActivatedBy><allowAccessByClinicalStaff>true</allowAccessByClinicalStaff><painQualityToday><painQuality>TINGLING</painQuality></painQualityToday><treatments><treatment>Sleep Management</treatment></treatments></painEvent></painEvents> </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 );
    }

    
    private void doDelete( String patientId )
    {
        // TODO: delete from child tables (collection tables)
        hdrJdbcTemplate.update( "DELETE FROM PAIN_EVENT WHERE PATIENT_IDENTITY = '" + patientId + "'" );
    }


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

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPainEventBuilderFactory factory = new HAPainEventBuilderFactory();
        factory.setPainEventBuilder( new HAPainEventBuilder( recordIdentifier, entryDate ) );
        domainEntryPointsWrappersMap.put( "PainEvent", 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.PainEvent );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAPainEventBuilderFactory factory = new HAPainEventBuilderFactory();
        factory.setPainEventBuilder( new HAPainEventBuilder() );

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