

package gov.va.med.cds.client.functional.vim.ha;


import static gov.va.med.cds.testharness.xml.Assert.assertNoErrors;
import static gov.va.med.cds.testharness.xml.Assert.assertXmlSimilar;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.client.functional.AbstractDataGeneratorValidatorTest;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.junit.runners.BeforeTestsOnce;
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.AbstractEntryPointBuilder;
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.HAAssessmentDocumentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HACalendarEventBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAClinicalDomainBuilderFactoryInterface;
import gov.va.med.cds.testharness.vhim400.builders.HAContactLogBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HADietJournalBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAExerciseJournalBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAGoalTrackingBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAMoodJournalBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainAssessmentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainEventBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainReassessmentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAVitalsBuilder;
import gov.va.med.cds.testharness.vhim400.builders.PatientEnteredDailyEventBuilder;
import gov.va.med.cds.testharness.xml.XmlValidationException;
import gov.va.med.cds.testharness.xml.XmlValidator;

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

import javax.xml.transform.TransformerConfigurationException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;


@ContextConfiguration( locations = { "classpath:gov/va/med/cds/client/functional/testDataGeneratorContext.xml",
                "classpath:gov/va/med/cds/config/nonWeblogicHdr2DataSourceContext.xml" } )
@RunWith( SuiteAwareSpringRunner.class )
public abstract class AbstractHaClientTest
    extends
        AbstractDataGeneratorValidatorTest
{
    private static final String ASSIGNING_AUTHORITY = "USDOD";
    private static final String ASSIGNING_FACILITY = "200DOD";
    private static final String LOGICAL_DELETE_RECORD_STATUS = "1";
    private static final String DELETE_RECORD_STATUS = "0";
    private static final String CREATED_RECORD_IDENTIFIER_XPATH = "/clinicaldata:ClinicalData/recordIdentifiers/recordIdentifier";
    private static final String PATIENT_IDENTIFIER_XPATH = "//patient/identifier";

    // HA Patient Journal constants
    private static final String PATIENT_JOURNAL_CLINICALLY_RELEVANT_DATE_XPATH = "//observationDate";
    private static final String PATIENT_JOURNAL_DOMAIN_RECORD_XPATH = "//genericJournalEntryDetails";

    // HA PatientEnteredVitalSign Domain constants
    private static final String PATIENT_ENTERED_VITAL_SIGN_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PatientEnteredVitalSign.getName();
    private static final String PATIENT_ENTERED_VITAL_SIGN_CLINICALLY_RELEVANT_DATE_XPATH = "//observationTime";
    private static final String PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH = "//vitalSignObservationEvent";
    private static final String VITAL_SIGN_TABLE_NAME = "VITAL_SIGN";
    private static final String QUALIFIER_TABLE_NAME = "QUALIFIER";
    private static final String VITAL_SIGN_ID = "VITAL_SIGN_ID";

    // HA Calendar Domain constants
    private static final String CALENDAR_EVENT_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.CalendarEvent.getName();
    private static final String CALENDAR_EVENT_CLINICALLY_RELEVANT_DATE_XPATH = "//calendarEventStartDate";
    private static final String CALENDAR_EVENT_DOMAIN_RECORD_XPATH = "//calendarEvent";

    // HA Pain Reassessment Domain constants
    private static final String PAIN_REASSESSMENT_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PainReassessment.getName();
    private static final String PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH = "//painReassessments/painReassessment";
    private static final String PAIN_REASSESSMENT_DATETIME_XPATH = "//reassessmentDate";
    private static final String PAIN_REASSESSMENT_TABLE_NAME = "PAIN_REASSESSMENT";

    //HA Pain Assessment Domain constants
    private static final String PAIN_ASSESSMENT_TABLE_NAME = "PAIN_ASSESSMENT";
    private static final String PAIN_ASSESSMENT_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PainAssessment.getName();
    private static final String PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH = "//painAssessments/painAssessment";
    private static final String PAIN_ASSESSMENT_DATETIME_XPATH = "//assessmentDate";

    private static final String PATIENT_ENTERED_CONTACT_LOG_JOURNAL_ENTRY_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID
                    + "-" + DomainEntryPoint.PatientEnteredContactLogJournalEntry.getName();
    private static final String PATIENT_ENTERED_DAILY_EVENT_ENTRY_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PatientEnteredDailyEventJournalEntry.getName();
    private static final String PATIENT_ENTERED_DIET_JOURNAL_ENTRY_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PatientEnteredDietJournalEntry.getName();
    private static final String PATIENT_ENTERED_EXERCISE_JOURNAL_ENTRY_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PatientEnteredExerciseJournalEntry.getName();
    private static final String PATIENT_ENTERED_MOOD_JOURNAL_ENTRY_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PatientEnteredMoodJournalEntry.getName();

    // HA Assessment Document Domain constants
    private static final String ASSESSMENT_DOCUMENT_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.AssessmentDocument.getName();
    private static final String ASSESSMENT_DOCUMENT_CLINICALLY_RELEVANT_DATE_XPATH = "//assessmentDateTime";
    private static final String ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH = "//assessmentDocument";
    private static final String ASSESSMENT_DOCUMENT_TABLE_NAME = "ASSESSMENT_DOCUMENT";

    //HA Skill tracking Domain constants
    private static final String SKILL_TRACKING_TABLE_NAME = "SKILL_TRACKING";
    private static final String SKILL_TRACKING_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.SkillTracking.getName();
    private static final String SKILL_TRACKING_DOMAIN_RECORD_XPATH = "//skillsTracking/skillTracking";

    //HA Pain Event Domain constants
    private static final String PAIN_EVENT_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.PainEvent.getName();
    private static final String PAIN_EVENT_CLINICALLY_RELEVANT_DATE_XPATH = "//entryDate";
    private static final String PAIN_EVENT_DOMAIN_RECORD_XPATH = "//painEvents/painEvent";
    private static final String PAIN_EVENT_TABLE_NAME = "PAIN_EVENT";

    //HA Goal tracking Domain constants
    private static final String GOAL_TRACKING_TABLE_NAME = "GOAL_TRACKING";
    private static final String GOAL_TRACKING_SUBSTITUTION_KEY = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID + "-"
                    + DomainEntryPoint.GoalTracking.getName();
    private static final String GOAL_TRACKING_DOMAIN_RECORD_XPATH = "//goalsTracking/goalTracking";

    @Autowired
    private JdbcTemplate hdrJdbcTemplate;


    @Test
    @BeforeTestsOnce
    @Suite( groups = "appservertest" )
    public void testIsAlive( )
    {
        assertTrue( clinicalDataService.isAlive() );
    }


    /**
     * Test to create, read and delete record for PatientEnteredVitalSigns
     */
    @Test
    @Suite( groups = "appservertest" )
    public void testPatientEnteredVitalSigns( )
        throws Exception
    {
        doDeleteWithChildRecords( VITAL_SIGN_TABLE_NAME, QUALIFIER_TABLE_NAME, VITAL_SIGN_ID, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        PATIENT_ENTERED_VITAL_SIGN_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        //Document expectedReadResultModified = dataGenerator.modifyTemplateMetaDataOfCRUADResultDocument( readTemplateId, createRequestModified);  
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified,
                        PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH, createdRecordIdentifier );

        // Make a read request with basic filter
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, PATIENT_ENTERED_VITAL_SIGN_CLINICALLY_RELEVANT_DATE_XPATH );
        String readFilter = createFilter( filterId, createRequest, clinicalObservationDate, DomainEntryPoint.PatientEnteredVitalSign.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //NOW update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface vitalsFactoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.PatientEnteredVitalSign.getName() );
        vitalsFactoryBuilder.setBuilder( new HAVitalsBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        PATIENT_ENTERED_VITAL_SIGN_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        //workAround until we have qualifier updates - currently functionality is always appending qualifiers to existing set - with duplicates
        combineCreateAndUpdateQualifiers( updateRequestModified, createRequestModified );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, PATIENT_ENTERED_VITAL_SIGN_CLINICALLY_RELEVANT_DATE_XPATH );
        readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.PatientEnteredVitalSign.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PatientEnteredVitalSign,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PatientEnteredVitalSign,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH ) );

        //validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, PATIENT_ENTERED_VITAL_SIGN_DOMAIN_RECORD_XPATH ) );
    }


    @SuppressWarnings( "unchecked" )
    private void combineCreateAndUpdateQualifiers( Document updateRequestModified, Document createRequestModified )
    {

        List<Element> qualifiers = createRequestModified.selectNodes( "//qualifiers/qualifier" );
        Element qualifiersElement = ( Element )updateRequestModified.selectSingleNode( "//qualifiers" );

        /*
         * need to merge qualifiers - create may have created a qualifier that was not included in the update - therefore a delete would NOT
         * have happened and a read will return all qualifiers - so they need to be merged in the expected results to match a read result
         */
        for ( Element q : qualifiers )
        {
            //first test if code present in update - if not add the qualifier from create into update
            String codeValue = q.element( "value" ).elementText( "code" );
            List<Element> updatedQualifiers = qualifiersElement.selectNodes( "qualifier" );
            boolean exists = false;
            for ( Element upQ : updatedQualifiers )
            {

                if ( ( upQ.element( "value" ).elementText( "code" ) ).equals( codeValue ) )
                {
                    exists = true;
                    break;
                }
            }
            if ( !exists )
            {
                Element qualifier = DocumentHelper.createElement( "qualifier" );
                Element value = DocumentHelper.createElement( "value" );
                value.addElement( "code" ).setText( codeValue );
                value.addElement( "displayText" ).setText( q.element( "value" ).elementText( "displayText" ) );
                value.addElement( "codingSystem" ).setText( q.element( "value" ).elementText( "codingSystem" ) );
                qualifier.add( value );
                qualifiersElement.add( qualifier );
            }

        }
    }


    @Test
    @Suite( groups = "appservertest" )
    public void testPatientEnteredVitalSignRead( )
        throws Exception
    {
        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;

        String[] hdrPatient1 = { "USDOD", "200DOD", "test_sourceid_999999" };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        //Filter with no dates
        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "PatientEnteredVitalSign" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients );
        String result = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        assertTrue( DocumentHelper.parseText( result ).selectNodes( "//patientEnteredVitalSigns/patientEnteredVitalSign" ).size() > 0 );

        //Filter with reduced dates test 1
        entryPointFilter.clear();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "PatientEnteredVitalSign" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-15Z" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-16Z" );

        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients );
        result = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        assertTrue( DocumentHelper.parseText( result ).selectNodes( "//patientEnteredVitalSigns/patientEnteredVitalSign" ).size() > 0 );

        //Filter with dates test 2
        entryPointFilter.clear();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "PatientEnteredVitalSign" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-15Z" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-17Z" );

        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients );
        result = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        assertTrue( DocumentHelper.parseText( result ).selectNodes( "//patientEnteredVitalSigns/patientEnteredVitalSign" ).size() > 0 );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for CalendarEvent
     */
    public void testCalendarEvent( )
        throws Exception
    {
        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        CALENDAR_EVENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        //Document expectedReadResultModified = dataGenerator.modifyTemplateMetaDataOfCRUADResultDocument( readTemplateId, createRequestModified);  
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, CALENDAR_EVENT_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        // Make a read request with basic filter
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, CALENDAR_EVENT_CLINICALLY_RELEVANT_DATE_XPATH );
        String readFilter = createFilter( filterId, createRequest, clinicalObservationDate, DomainEntryPoint.CalendarEvent.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //NOW update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface calendarFactoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.CalendarEvent.getName() );
        calendarFactoryBuilder.setBuilder( new HACalendarEventBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        CALENDAR_EVENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, CALENDAR_EVENT_CLINICALLY_RELEVANT_DATE_XPATH );
        readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.CalendarEvent.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.CalendarEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.CalendarEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, CALENDAR_EVENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, CALENDAR_EVENT_DOMAIN_RECORD_XPATH ) );

        //validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, CALENDAR_EVENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, CALENDAR_EVENT_DOMAIN_RECORD_XPATH ) );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for AssessmentTotalScore
     */
    public void testPainReassessment( )
        throws Exception
    {
        // cleanup existing data, if any
        doDelete( PAIN_REASSESSMENT_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        PAIN_REASSESSMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        // Make a read request with basic filter
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, PAIN_REASSESSMENT_DATETIME_XPATH );
        String readFilter = createFilter( filterId, createRequest, clinicalObservationDate, DomainEntryPoint.PainReassessment.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //NOW update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface factoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.PainReassessment.getName() );
        factoryBuilder.setBuilder( new HAPainReassessmentBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        PAIN_REASSESSMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, PAIN_REASSESSMENT_DATETIME_XPATH );
        readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.PainReassessment.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainReassessment,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainReassessment,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH ) );

        //validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, PAIN_REASSESSMENT_DOMAIN_RECORD_XPATH ) );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for Pain Assessment
     */
    public void testPainAssessment( )
        throws Exception
    {
        // cleanup existing data, if any
        doDelete( PAIN_ASSESSMENT_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        PAIN_ASSESSMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        // Make a read request with basic filter
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, PAIN_ASSESSMENT_DATETIME_XPATH );
        String readFilter = createFilter( filterId, createRequest, clinicalObservationDate, DomainEntryPoint.PainAssessment.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //NOW update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface factoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.PainAssessment.getName() );
        factoryBuilder.setBuilder( new HAPainAssessmentBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        PAIN_ASSESSMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, PAIN_ASSESSMENT_DATETIME_XPATH );
        readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.PainAssessment.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainAssessment,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainAssessment,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH ) );

        //validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, PAIN_ASSESSMENT_DOMAIN_RECORD_XPATH ) );

    }


    @SuppressWarnings( "unused" )
    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete AssessmentDocument domain
     */
    public void testAssessmentDocument( )
        throws Exception
    {
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";

        // cleanup existing data, if any
        doDelete( ASSESSMENT_DOCUMENT_TABLE_NAME, uniquePatientIdentity );

        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_READ1_TEMPLATE;
        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        ASSESSMENT_DOCUMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified,
                        ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH, createdRecordIdentifier );

        // Make a read request using detail filter/template
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, ASSESSMENT_DOCUMENT_CLINICALLY_RELEVANT_DATE_XPATH );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
        entryPointFilterMap.put( FilterBuilder.RECORD_IDENTITY, createdRecordIdentifier.elementText( "identity" ) );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilterMap.put( FilterBuilder.PATIENT_CENTRIC_KEY, "false" );

        String readFilter = createDetailFilter( filterId, entryPointFilterMap, clientRequestInitiationTime );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //NOW update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface factoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.AssessmentDocument.getName() );
        factoryBuilder.setBuilder( new HAAssessmentDocumentBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        ASSESSMENT_DOCUMENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, ASSESSMENT_DOCUMENT_CLINICALLY_RELEVANT_DATE_XPATH );
        //readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.AssessmentDocument.getName(), PATIENT_IDENTIFIER_XPATH, ASSESSMENT_DOCUMENT_SPECIALIZED_DOMAIN_ENTRY_POINT );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.AssessmentDocument,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.AssessmentDocument,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_READ1_TEMPLATE );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH ) );

        //validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_READ1_TEMPLATE );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, ASSESSMENT_DOCUMENT_DOMAIN_RECORD_XPATH ) );

    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to read existing test data by: 
     *  1. date range 
     *  2. optional parameter category  
     *  3. date range plus optional parameter category
     */
    public void testAssessmentDocumentDateAndCategoryReads( )
        throws Exception
    {
        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        String specializedDomainEntryPoint = "filter:assessmentDocumentDomainEntryPointFilter";
        String categoryKey = "category";
        String categoryText = "Pain Reassessment";

        String[] hdrPatient1 = { "USDOD", "200DOD", "test_sourceid_1000000" };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        //1. Dates only
        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-17" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-17" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint );
        String result = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );

        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        // assertTrue( DocumentHelper.parseText( result ).selectNodes( "//assessmentDocuments/assessmentDocument" ).size() == 4 );

        //2. Category only
        entryPointFilter.clear();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        Map<String, String> optionalQueryParameters = new HashMap<String, String>();
        optionalQueryParameters.put( categoryKey, categoryText );

        filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint,
                        optionalQueryParameters );
        result = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );

        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        //assertTrue( DocumentHelper.parseText( result ).selectNodes( "//assessmentDocuments/assessmentDocument"  ).size() == 2 );

        //3. Category and Dates
        entryPointFilter.clear();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-17" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-17" );

        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        optionalQueryParameters.clear();
        optionalQueryParameters.put( categoryKey, categoryText );

        filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint,
                        optionalQueryParameters );
        result = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );

        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );
        //assertTrue( DocumentHelper.parseText( result ).selectNodes( "//assessmentDocuments/assessmentDocument"  ).size() == 1 );

    }


    @Test
    @Suite( groups = "appservertest" )
    public void testSkillTracking( )
        throws Exception
    {
        // cleanup existing data, if any
        doDelete( SKILL_TRACKING_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        SKILL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, "Stretching" );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        //get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        ///Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, SKILL_TRACKING_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        // Make a read request
        requestId = TemplateIdHelper.getUniqueIdentifier();
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        String specializedDomainEntryPoint = "filter:skillTrackingDomainEntryPointFilter";

        String[] hdrPatient1 = { "USDOD", "200DOD", uniquePatientIdentity };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "SkillTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );
        //No updates are done by client for this domain. Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainAssessment,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.SkillTracking,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( createReadResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, SKILL_TRACKING_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, SKILL_TRACKING_DOMAIN_RECORD_XPATH ) );

    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to read existing test data by: 
     *  2. optional parameter skillType  
     *  3. skill history
     */
    public void testSkillTrackingReads( )
        throws Exception
    {
        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        String specializedDomainEntryPoint = "filter:skillTrackingDomainEntryPointFilter";
        String skillTypeKey = "skillType";
        String skillTypeText = "Stretching";

        String[] hdrPatient1 = { "USDOD", "200DOD", uniquePatientIdentity };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        //1. Skill type only

        // cleanup existing data, if any
        doDelete( SKILL_TRACKING_TABLE_NAME, uniquePatientIdentity );

        requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        SKILL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, "Stretching" );

        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        //Thread.sleep( 10000 );
        requestId = TemplateIdHelper.getUniqueIdentifier();
        createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        SKILL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, "Stretching" );

        createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );
        Element createdRecordIdentifier1 = extractRecordIdentifier( createResult );

        requestId = TemplateIdHelper.getUniqueIdentifier();
        createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        SKILL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, "Activity Pacing" );

        createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );
        Element createdRecordIdentifier2 = extractRecordIdentifier( createResult );

        requestId = TemplateIdHelper.getUniqueIdentifier();
        createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        SKILL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, "Activity Pacing" );

        createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );
        Element createdRecordIdentifier3 = extractRecordIdentifier( createResult );

        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "SkillTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint, null );
        String result = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );
        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );

        Document clinicalDataDocument = DocumentHelper.parseText( result );
        List<Element> domainElements = clinicalDataDocument.selectNodes( "//skillType" );
        assertTrue( domainElements.size() > 0 );
        for ( Element domainElement : domainElements )
        {
            if ( domainElement.getText().equals( "Stretching" ) )
            {
                assertTrue( domainElement.getText().equals( "Stretching" ) );
            }
            else
            {
                assertTrue( domainElement.getText().equals( "Activity Pacing" ) );
            }

        }

        //2. Skill type history
        entryPointFilter.clear();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "SkillTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        Map<String, String> optionalQueryParameters = new HashMap<String, String>();
        optionalQueryParameters.put( skillTypeKey, skillTypeText );

        filterXml = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint,
                        optionalQueryParameters );
        result = clinicalDataService.readClinicalData( readTemplateId, filterXml, filterId, requestId );

        assertTrue( !result.contains( "<errorSection>" ) );
        XmlValidator.validateXml( result, readTemplateId );

        clinicalDataDocument = DocumentHelper.parseText( result );
        domainElements = clinicalDataDocument.selectNodes( "//skillType" );
        assertTrue( domainElements.size() == 2 );

        for ( Element domainElement : domainElements )
        {
            assertTrue( domainElement.getText().equals( "Stretching" ) );
            assertTrue( !domainElement.getText().equals( "Activity Pacing" ) );
        }

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.SkillTracking,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );
        assertNoErrors( physicalDeleteResult );

        physicalDelete = dataGenerator.getClinicalDataBuilder()
                        .deleteClinicalData( DomainEntryPoint.SkillTracking, TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                                        createdRecordIdentifier1.elementText( "identity" ), DELETE_RECORD_STATUS );
        physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(), TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                        requestId );
        assertNoErrors( physicalDeleteResult );

        physicalDelete = dataGenerator.getClinicalDataBuilder()
                        .deleteClinicalData( DomainEntryPoint.SkillTracking, TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                                        createdRecordIdentifier2.elementText( "identity" ), DELETE_RECORD_STATUS );
        physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(), TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                        requestId );
        assertNoErrors( physicalDeleteResult );

        physicalDelete = dataGenerator.getClinicalDataBuilder()
                        .deleteClinicalData( DomainEntryPoint.SkillTracking, TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                                        createdRecordIdentifier3.elementText( "identity" ), DELETE_RECORD_STATUS );
        physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(), TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                        requestId );
        assertNoErrors( physicalDeleteResult );
    }


    @Test
    @Suite( groups = "appservertest" )
    public void testPainEvent( )
        throws Exception
    {
        // cleanup existing data, if any
        doDelete( PAIN_EVENT_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        PAIN_EVENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        // Create record - and assert no errors, if that fails we should not move forward - all other asserts happen after delete cleanup at the end of method.
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        // get record identifier from create response
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        // Modify the createXML into and expected readXML - add patients element and insert the createdRecordIdentifier
        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        //Document expectedReadResultModified = dataGenerator.modifyTemplateMetaDataOfCRUADResultDocument( readTemplateId, createRequestModified);  
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, PAIN_EVENT_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        // Make a read request with basic filter
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String clinicalObservationDate = extractEntryFilterDate( createRequest, PAIN_EVENT_CLINICALLY_RELEVANT_DATE_XPATH );
        String readFilter = createFilter( filterId, createRequest, clinicalObservationDate, DomainEntryPoint.PainEvent.getName(),
                        PATIENT_IDENTIFIER_XPATH );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        // update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface painFactoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.PainEvent.getName() );
        painFactoryBuilder.setBuilder( new HAPainEventBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        PAIN_EVENT_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        combineCreateAndUpdatePainQualityAndTreatment( updateRequestModified, createRequestModified );
        String expectedUpdateReadResult = updateRequestModified.asXML();

        clinicalObservationDate = extractEntryFilterDate( updateRequest, PAIN_EVENT_CLINICALLY_RELEVANT_DATE_XPATH );
        readFilter = createFilter( filterId, updateRequest, clinicalObservationDate, DomainEntryPoint.PainEvent.getName(), PATIENT_IDENTIFIER_XPATH );
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        // logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        // validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, PAIN_EVENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, PAIN_EVENT_DOMAIN_RECORD_XPATH ) );

        // validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, PAIN_EVENT_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, PAIN_EVENT_DOMAIN_RECORD_XPATH ) );
    }


    @Test
    @Suite( groups = { "appservertest" } )
    public void testGoalTracking( )
        throws Exception
    {
        final String GOAL_NAME_1 = "Walk Daily";
        final String GOAL_NAME_2 = "Deep Breathing";

        doDelete( GOAL_TRACKING_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        GOAL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, GOAL_NAME_1, null );
        String createResult = clinicalDataService.createClinicalData( createRequest, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, requestId );
        assertNoErrors( createResult );

        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        Element createdRecordIdentifier = extractRecordIdentifier( createResult );

        Document createRequestModified = modifyCreateUpdateToRead( createRequest, readTemplateId );
        String expectedCreateReadResult = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, GOAL_TRACKING_DOMAIN_RECORD_XPATH,
                        createdRecordIdentifier );

        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String specializedDomainEntryPoint = "filter:goalTrackingDomainEntryPointFilter";

        String[] hdrPatient = { "USDOD", "200DOD", uniquePatientIdentity };
        String[][] patientIdentifiers = { hdrPatient };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "GoalTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint );
        String createReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        // update the record - first give the factory a new builder that will modify values using the created record identifier and patient
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface goalTrackingFactoryBuilder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( DomainEntryPoint.GoalTracking.getName() );
        goalTrackingFactoryBuilder.setBuilder( new HAGoalTrackingBuilder( createdRecordIdentifier.elementText( "identity" ) ) );

        String updateRequest = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        GOAL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, GOAL_NAME_2, null );
        String updateResult = clinicalDataService.updateClinicalData( updateRequest, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, requestId );

        Document updateRequestModified = modifyCreateUpdateToRead( updateRequest, readTemplateId );
        String expectedUpdateReadResult = updateRequestModified.asXML();
        String updateReadResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        // logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ),
                        LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( DomainEntryPoint.PainEvent,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, createdRecordIdentifier.elementText( "identity" ), DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertNoErrors( updateResult );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        // validate and compare create read response
        XmlValidator.validateXml( createReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( createReadResult, GOAL_TRACKING_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedCreateReadResult, GOAL_TRACKING_DOMAIN_RECORD_XPATH ) );

        // validate and compare update read response
        XmlValidator.validateXml( updateReadResult, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( updateReadResult, GOAL_TRACKING_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedUpdateReadResult, GOAL_TRACKING_DOMAIN_RECORD_XPATH ) );
    }


    @Test
    @Suite( groups = { "appservertest" } )
    public void testGoalTrackingReads( )
        throws Exception
    {
        final String GOAL_NAME_1 = "Walk Daily";
        final String GOAL_NAME_KEY = "goalName";

        doDelete( GOAL_TRACKING_TABLE_NAME, uniquePatientIdentity );

        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String templateId = TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID;
        String createRequest = dataGenerator.createPatientEnteredXml( requestId, templateId, GOAL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity,
                        ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, GOAL_NAME_1, "20120618090000-0700" );
        String createResult = clinicalDataService.createClinicalData( createRequest, templateId, requestId );
        assertNoErrors( createResult );

        createRequest = dataGenerator.createPatientEnteredXml( requestId, templateId, GOAL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity,
                        ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, GOAL_NAME_1, "20120619090000-0700" );
        createResult = clinicalDataService.createClinicalData( createRequest, templateId, requestId );
        assertNoErrors( createResult );

        createRequest = dataGenerator.createPatientEnteredXml( requestId, templateId, GOAL_TRACKING_SUBSTITUTION_KEY, uniquePatientIdentity,
                        ASSIGNING_AUTHORITY, ASSIGNING_FACILITY, GOAL_NAME_1, "20120620090000-0700" );
        createResult = clinicalDataService.createClinicalData( createRequest, templateId, requestId );
        assertNoErrors( createResult );

        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String specializedDomainEntryPoint = "filter:goalTrackingDomainEntryPointFilter";

        String[] hdrPatient = { "USDOD", "200DOD", uniquePatientIdentity };
        String[][] patientIdentifiers = { hdrPatient };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "GoalTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        String readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint );
        String readResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        assertNoErrors( readResult );

        Document clinicalDataDocument = DocumentHelper.parseText( readResult );
        assertTrue( clinicalDataDocument.selectNodes( GOAL_TRACKING_DOMAIN_RECORD_XPATH ).size() == 1 );
        assertTrue( clinicalDataDocument.selectSingleNode( "//goalsTracking/goalTracking/entryDate/literal" ).getText()
                        .equals( "20120620090000-0700" ) );

        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-06-18Z" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-06-19Z" );

        readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint );
        readResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        assertNoErrors( readResult );

        clinicalDataDocument = DocumentHelper.parseText( readResult );
        assertTrue( clinicalDataDocument.selectNodes( GOAL_TRACKING_DOMAIN_RECORD_XPATH ).size() == 1 );
        assertTrue( clinicalDataDocument.selectSingleNode( "//goalsTracking/goalTracking/entryDate/literal" ).getText()
                        .equals( "20120619090000-0700" ) );

        Map<String, String> optionalQueryParameters = new HashMap<String, String>();
        optionalQueryParameters.put( GOAL_NAME_KEY, GOAL_NAME_1 );

        readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint,
                        optionalQueryParameters );
        readResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        assertNoErrors( readResult );
        assertTrue( DocumentHelper.parseText( readResult ).selectNodes( GOAL_TRACKING_DOMAIN_RECORD_XPATH ).size() == 2 );

        entryPointFilter.remove( FilterBuilder.START_DATE_KEY );
        entryPointFilter.remove( FilterBuilder.END_DATE_KEY );
        readFilter = dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patients, specializedDomainEntryPoint,
                        optionalQueryParameters );
        readResult = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        assertNoErrors( readResult );
        assertTrue( DocumentHelper.parseText( readResult ).selectNodes( GOAL_TRACKING_DOMAIN_RECORD_XPATH ).size() == 3 );
    }


    @SuppressWarnings( "unchecked" )
    private void combineCreateAndUpdatePainQualityAndTreatment( Document updateRequestModified, Document createRequestModified )
    {
        List<Element> qualities = createRequestModified.selectNodes( "//painQualityToday/painQuality" );
        Element painQualityElement = ( Element )updateRequestModified.selectSingleNode( "//painQualityToday" );

        for ( Element quality : qualities )
        {
            //first test if code present in update - if not add the painQualityToday from create into update
            String painQualityValue = quality.getText();
            List<Element> updatedQualities = painQualityElement.elements();
            boolean exists = false;
            for ( Element updatedQuality : updatedQualities )
            {

                if ( ( updatedQuality.getText() ).equals( painQualityValue ) )
                {
                    exists = true;
                    break;
                }
            }
            if ( !exists )
            {
                Element painQuality = DocumentHelper.createElement( "painQuality" );
                painQuality.setText( painQualityValue );
                painQualityElement.add( painQuality );
            }

        }

        List<Element> treatments = createRequestModified.selectNodes( "//treatments/treatment" );
        Element treatmentElement = ( Element )updateRequestModified.selectSingleNode( "//treatments" );

        for ( Element treatment : treatments )
        {
            //first test if code present in update - if not add the painTreatment from create into update
            String treatmentValue = treatment.getText();
            List<Element> updatedTreatments = treatmentElement.elements();
            boolean exists = false;
            for ( Element updatedTreatment : updatedTreatments )
            {

                if ( ( updatedTreatment.getText() ).equals( treatmentValue ) )
                {
                    exists = true;
                    break;
                }
            }
            if ( !exists )
            {
                Element painTreatment = DocumentHelper.createElement( "treatment" );
                painTreatment.setText( treatmentValue );
                treatmentElement.add( painTreatment );
            }

        }

    }


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


    private void doDeleteWithChildRecords( String parentTableName, String childTableName, String parentFK, String patientId )
    {
        hdrJdbcTemplate.update( "DELETE FROM " + childTableName + " C WHERE C." + parentFK + " = (SELECT " + parentFK + " FROM " + parentTableName
                        + " P WHERE P.PATIENT_IDENTITY = '" + patientId + "')" );
        doDelete( parentTableName, patientId );
    }


    protected String createFilter( String filterId, String requestXml, String clinicallyRelevantDate, String domainName, String patientIdentifierXpath )
        throws DocumentException
    {
        return createFilter( filterId, requestXml, clinicallyRelevantDate, domainName, patientIdentifierXpath, null );
    }


    protected String createFilter( String filterId, String requestXml, String clinicallyRelevantDate, String domainName,
                    String patientIdentifierXpath, String specializedDomainEntryFilter )
        throws DocumentException
    {
        return createFilter( filterId, requestXml, clinicallyRelevantDate, domainName, patientIdentifierXpath, specializedDomainEntryFilter, null );
    }


    protected String createFilter( String filterId, String requestXml, String clinicallyRelevantDate, String domainName,
                    String patientIdentifierXpath, String specializedDomainEntryFilter, Map<String, String> optionalQueryParameters )
        throws DocumentException
    {
        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, domainName );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );

        //this will give us a 24 hour period
        entryPointFilter.put( FilterBuilder.START_DATE_KEY, clinicallyRelevantDate );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, clinicallyRelevantDate );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilter );

        Map<String, String> patientMap = extractPatientMap( requestXml, patientIdentifierXpath );
        List<Map<String, String>> patientMapList = new ArrayList<Map<String, String>>();
        patientMapList.add( patientMap );

        return dataGenerator.createFilterWithEdiPi( filterId, entryPointFilterMaps, patientMapList, specializedDomainEntryFilter,
                        optionalQueryParameters );
    }


    private String extractEntryFilterDate( String createRequest, String observationDateXPath )
        throws DocumentException
    {
        Document createDoc = DocumentHelper.parseText( createRequest );
        Element observationDate = ( Element )createDoc.selectSingleNode( observationDateXPath );
        String observationTimestamp = observationDate.elementText( "literal" );
        String year = observationTimestamp.substring( 0, 4 );
        String month = observationTimestamp.substring( 4, 6 );
        String day = observationTimestamp.substring( 6, 8 );
        String tzh = observationTimestamp.substring( 14, 17 );
        String tzm = observationTimestamp.substring( 17, 19 );

        return year + "-" + month + "-" + day + tzh + ":" + tzm;
    }


    protected Map<String, String> extractPatientMap( String createRequest, String patientIdentifierPath )
        throws DocumentException
    {
        Document createDoc = DocumentHelper.parseText( createRequest );
        Element patientIdentifier = ( Element )createDoc.selectSingleNode( patientIdentifierPath );

        Map<String, String> patientMap = new HashMap<String, String>();
        String identity = patientIdentifier.element( "identity" ).getText();
        String assignignAuthority = patientIdentifier.element( "assigningAuthority" ).getText();
        String assignFacility = patientIdentifier.element( "assigningFacility" ).getText();
        patientMap.put( FilterBuilder.IDENTITY, identity );
        patientMap.put( FilterBuilder.ASSIGNING_AUTHORITY_KEY, assignignAuthority );
        patientMap.put( FilterBuilder.ASSIGNING_FACILITY, assignFacility );

        return patientMap;
    }


    @SuppressWarnings( "unchecked" )
    protected Document modifyCreateUpdateToRead( String createUpdateRequest, String readTemplateId )
        throws DocumentException
    {
        Document createUpdateResultDoc = DocumentHelper.parseText( createUpdateRequest );
        Element rootElement = createUpdateResultDoc.getRootElement();

        Element templateIdElement = rootElement.element( "templateId" );
        templateIdElement.setText( readTemplateId );

        Element clientNameElement = rootElement.element( "clientName" );
        if ( clientNameElement != null )
        {
            clientNameElement.detach();
        }

        Element clientRequestInitiationTimeElement = rootElement.element( "clientRequestInitiationTime" );
        if ( clientRequestInitiationTimeElement != null )
        {
            clientRequestInitiationTimeElement.detach();
        }

        List<Node> nodes = rootElement.selectNodes( "//hexBinaryAttachment" );
        for ( Node node : nodes )
        {
            node.detach();
        }

        Element patient = ( Element )rootElement.selectSingleNode( "//patient" ).detach();

        Element patients = DocumentHelper.createElement( "patients" );
        patients.add( patient );
        rootElement.add( patients );
        return createUpdateResultDoc;
    }


    @SuppressWarnings( "unchecked" )
    protected Element extractRecordIdentifier( String createResult )
        throws DocumentException
    {
        Document createResultDoc = DocumentHelper.parseText( createResult );

        List<Element> recordIdentifierList = createResultDoc.selectNodes( CREATED_RECORD_IDENTIFIER_XPATH );
        return ( Element )recordIdentifierList.get( 0 ).detach();
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for PatientEnteredContactLogJournalEntry
     */
    public void testPatientEnteredContactLogJournalEntry( )
        throws Exception
    {
        String table = "CONTACT_LOG_JOURNAL";
        String substitutionKey = PATIENT_ENTERED_CONTACT_LOG_JOURNAL_ENTRY_SUBSTITUTION_KEY;
        DomainEntryPoint domainEntryPoint = DomainEntryPoint.PatientEnteredContactLogJournalEntry;
        testJournalDomainCRUD( table, substitutionKey, domainEntryPoint );
    }


    @Test
    @Suite( groups = "appservertest" )
    public void testPatientEnteredDailyEventJournalEntry( )
        throws Exception
    {
        String table = "DAILY_EVENT_JOURNAL";
        String substitutionKey = PATIENT_ENTERED_DAILY_EVENT_ENTRY_SUBSTITUTION_KEY;
        DomainEntryPoint domainEntryPoint = DomainEntryPoint.PatientEnteredDailyEventJournalEntry;
        testJournalDomainCRUD( table, substitutionKey, domainEntryPoint );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for PatientEnteredExerciseJournalEntry
     */
    public void testPatientEnteredDietJournalEntry( )
        throws Exception
    {
        String table = "DIET_JOURNAL";
        String substitutionKey = PATIENT_ENTERED_DIET_JOURNAL_ENTRY_SUBSTITUTION_KEY;
        DomainEntryPoint domainEntryPoint = DomainEntryPoint.PatientEnteredDietJournalEntry;
        testJournalDomainCRUD( table, substitutionKey, domainEntryPoint );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for PatientEnteredExerciseJournalEntry
     */
    public void testPatientEnteredExerciseJournalEntry( )
        throws Exception
    {
        String table = "EXERCISE_JOURNAL";
        String substitutionKey = PATIENT_ENTERED_EXERCISE_JOURNAL_ENTRY_SUBSTITUTION_KEY;
        DomainEntryPoint domainEntryPoint = DomainEntryPoint.PatientEnteredExerciseJournalEntry;
        testJournalDomainCRUD( table, substitutionKey, domainEntryPoint );
    }


    @Test
    @Suite( groups = "appservertest" )
    /**
     * Test to create, read and delete record for PatientEnteredMoodJournalEntry
     */
    public void testPatientEnteredMoodJournalEntry( )
        throws Exception
    {
        String table = "MOOD_JOURNAL";
        String substitutionKey = PATIENT_ENTERED_MOOD_JOURNAL_ENTRY_SUBSTITUTION_KEY;
        DomainEntryPoint domainEntryPoint = DomainEntryPoint.PatientEnteredMoodJournalEntry;
        testJournalDomainCRUD( table, substitutionKey, domainEntryPoint );
    }


    @SuppressWarnings( "unused" )
    protected void testJournalDomainCRUD( String table, String substitutionKey, DomainEntryPoint domainEntryPoint )
        throws DocumentException,
            XmlValidationException,
            TransformerConfigurationException,
            IOException
    {

        ///SETUP
        String patientId = uniquePatientIdentity + "_" + ( ( int )( Math.random() * 10000000 ) );
        String domainEntryPointName = domainEntryPoint.getName();
        String requestId = TemplateIdHelper.getUniqueIdentifier();
        String readTemplateId = TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID;
        String readTemplateIdDetails = TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID;
        String filterId = TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER;
        String filterIdDetails = TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_FILTER;

        doDelete( table, patientId );

        /// CREATE
        String createRequestXml = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        substitutionKey, patientId, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );
        String createResponseXml = clinicalDataService.createClinicalData( createRequestXml, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        requestId );
        assertNoErrors( createResponseXml );

        /// EXTRACT Elements
        Document createRequest = DocumentHelper.parseText( createRequestXml );
        String attachmentName = ( ( Element )createRequest.selectSingleNode( "//binaryAttachment/name" ) ).getTextTrim();
        Element originalBinaryAttachment = ( Element )createRequest.selectSingleNode( "//binaryAttachment" ).detach(); //for later use in putting together the expected read response after update
        Element recordIdentifier = extractRecordIdentifier( createResponseXml );
        String recordId = recordIdentifier.elementText( "identity" );

        /// ASSEMBLE EXPECTED READ RESPONSE
        Document createRequestModified = convertCreateRequestToExpectedJournalRead( createRequestXml, readTemplateId, patientId, false );
        String expectedReadResponseXml = dataGenerator.insertCreatedRecordIdentifier( createRequestModified, PATIENT_JOURNAL_DOMAIN_RECORD_XPATH,
                        recordIdentifier );

        /// ASSEMBLE EXPECTED READ RESPONSE DETAILS
        Document createRequestModifiedDetails = convertCreateRequestToExpectedJournalRead( createRequestXml, readTemplateIdDetails, patientId, true );
        String expectedReadResponseDetailsXml = dataGenerator.insertCreatedRecordIdentifier( createRequestModifiedDetails,
                        PATIENT_JOURNAL_DOMAIN_RECORD_XPATH, recordIdentifier.createCopy() );

        /// GET READ RESPONSE
        String clinicalObservationDate = extractEntryFilterDate( createRequestXml, PATIENT_JOURNAL_CLINICALLY_RELEVANT_DATE_XPATH );
        String readFilter = createFilter( filterId, createRequestXml, clinicalObservationDate, domainEntryPointName, PATIENT_IDENTIFIER_XPATH );
        String actualReadResponse = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );

        /// GET READ RESPONSE DETAILS
        Map<String, String> otherQueryParameters = new HashMap<String, String>();
        otherQueryParameters.put( "attachmentName", attachmentName );
        String detailFilterXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( domainEntryPointName, recordId, otherQueryParameters );

        String actualReadResponseDetailsXml = clinicalDataService.readClinicalData( readTemplateIdDetails, detailFilterXml, filterIdDetails,
                        requestId );
        int attachmentsBeforeUpdateCount = DocumentHelper.parseText( actualReadResponseDetailsXml ).selectNodes( "//binaryAttachment" ).size();

        /// GET READ RESPONSE DETAILS
        String detailFilterXmlWithoutName = FilterBuilder.buildHealthAdapterJournalDetailsFilter( domainEntryPointName, recordId, null );
        String actualReadResponseDetailsWithoutNameXml = clinicalDataService.readClinicalData( readTemplateIdDetails, detailFilterXmlWithoutName,
                        filterIdDetails, requestId );

        /// UPDATE
        Map<String, ClinicalDomainBuilderFactoryInterface> clinicalDataBuilderFactories = dataGenerator.getClinicalDataBuilder()
                        .getDomainEntryPointsWrappersMap();
        HAClinicalDomainBuilderFactoryInterface builder = ( HAClinicalDomainBuilderFactoryInterface )clinicalDataBuilderFactories
                        .get( domainEntryPointName );
        builder.setBuilder( getJournalBuilder( domainEntryPoint, recordId )/*new HAContactLogBuilder( recordId )*/);
        String updateRequestXml = dataGenerator.createPatientEnteredXml( requestId, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        substitutionKey, patientId, ASSIGNING_AUTHORITY, ASSIGNING_FACILITY );

        String updateResponseXml = clinicalDataService.updateClinicalData( updateRequestXml, TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID,
                        requestId );

        /// ASSEMBLE EXPECTED READ RESPONSE AFTER UPDATE
        Document expectedReadResponseAfterUpdate = convertUpdateRequestToExpectedJournalRead( updateRequestXml, readTemplateIdDetails,
                        originalBinaryAttachment );
        String expectedReadResponseAfterUpdateXml = expectedReadResponseAfterUpdate.asXML();

        /// READ AFTER UPDATE
        clinicalObservationDate = extractEntryFilterDate( updateRequestXml, PATIENT_JOURNAL_CLINICALLY_RELEVANT_DATE_XPATH );
        readFilter = createFilter( filterId, updateRequestXml, clinicalObservationDate, domainEntryPointName, PATIENT_IDENTIFIER_XPATH );
        String actualReadResponseAfterUpdateXml = clinicalDataService.readClinicalData( readTemplateId, readFilter, filterId, requestId );
        Document actualReadResponseAfterUpdate = DocumentHelper.parseText( actualReadResponseAfterUpdateXml );
        int attachmentsReadAfterUpdateCount = actualReadResponseAfterUpdate.selectNodes( "//binaryAttachment" ).size();

        /// DETAILED READ AFTER UPDATE WITH NAME
        String detailFilterAfterUpdateXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( domainEntryPointName, recordId,
                        otherQueryParameters );

        String actualReadResponseAfterUpdateWithNameXml = clinicalDataService.readClinicalData( readTemplateIdDetails, detailFilterAfterUpdateXml,
                        filterIdDetails, requestId );
        int attachmentsAfterUpdateWithNameCount = DocumentHelper.parseText( actualReadResponseAfterUpdateWithNameXml )
                        .selectNodes( "//binaryAttachment" ).size();

        /// DETAILED READ AFTER UPDATE WITHOUT NAME
        String detailFilterAfterUpdateWithoutNameXml = FilterBuilder.buildHealthAdapterJournalDetailsFilter( domainEntryPointName, recordId, null );
        String actualReadResponseAfterUpdateWithoutNameXml = clinicalDataService.readClinicalData( readTemplateIdDetails,
                        detailFilterAfterUpdateWithoutNameXml, filterIdDetails, requestId );
        int attachmentsAfterUpdateWithoutNameCount = DocumentHelper.parseText( actualReadResponseAfterUpdateWithoutNameXml )
                        .selectNodes( "//binaryAttachment" ).size();

        //Now logically delete and read and ensure no record is returned
        Document logicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( domainEntryPoint,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordId, LOGICAL_DELETE_RECORD_STATUS );
        String logicalDeleteResult = clinicalDataService.deleteClinicalData( logicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        //clean up the data - delete the record   
        Document physicalDelete = dataGenerator.getClinicalDataBuilder().deleteClinicalData( domainEntryPoint,
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordId, DELETE_RECORD_STATUS );
        String physicalDeleteResult = clinicalDataService.deleteClinicalData( physicalDelete.asXML(),
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, requestId );

        // Make assertions and validations
        assertTrue( attachmentsBeforeUpdateCount == 1 );
        assertTrue( attachmentsReadAfterUpdateCount >= 2 );
        assertTrue( attachmentsAfterUpdateWithNameCount >= 1 );
        assertTrue( attachmentsAfterUpdateWithoutNameCount >= 2 );
        assertNoErrors( updateResponseXml );
        assertNoErrors( logicalDeleteResult );
        assertNoErrors( physicalDeleteResult );

        //validate and compare create read response
        XmlValidator.validateXml( actualReadResponse, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID );
        assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( actualReadResponse, PATIENT_JOURNAL_DOMAIN_RECORD_XPATH ),
                        detachNodesFromHealthAdapterRead1Result( expectedReadResponseXml, PATIENT_JOURNAL_DOMAIN_RECORD_XPATH ) );

        /*        //validate and compare create read response details
                XmlValidator.validateXml( actualReadResponseAfterUpdateWithoutNameXml, TemplateIdHelper.HEALTH_ADAPTER_JOURNAL_DETAIL_READ1_TEMPLATE_ID );
                assertXmlSimilar( detachNodesFromHealthAdapterRead1Result( actualReadResponseAfterUpdateWithoutNameXml, PATIENT_JOURNAL_DOMAIN_RECORD_XPATH ),
                                detachNodesFromHealthAdapterRead1Result( expectedReadResponseAfterUpdateXml, PATIENT_JOURNAL_DOMAIN_RECORD_XPATH ) );
        */
    }


    private AbstractEntryPointBuilder getJournalBuilder( DomainEntryPoint domainEntryPoint, String recordId )
    {
        switch ( domainEntryPoint )
        {
        case PatientEnteredContactLogJournalEntry:
        {
            return new HAContactLogBuilder( recordId );
        }
        case PatientEnteredMoodJournalEntry:
        {
            return new HAMoodJournalBuilder( recordId, "UPDATE", null );
        }
        case PatientEnteredDietJournalEntry:
        {
            return new HADietJournalBuilder( recordId, "UPDATE" );
        }
        case PatientEnteredExerciseJournalEntry:
        {
            return new HAExerciseJournalBuilder( recordId, "UPDATE" );
        }
        case PatientEnteredDailyEventJournalEntry:
        {
            return new PatientEnteredDailyEventBuilder( recordId );
        }
        default:
            break;
        }
        throw new RuntimeException( "Method only applies to Health Adapter Journal Domains" );
    }


    protected Document convertUpdateRequestToExpectedJournalRead( String updateRequestXml, String readTemplateId, Element originalBinaryAttachment )
        throws DocumentException
    {
        Document updateRequest = DocumentHelper.parseText( updateRequestXml );
        Element rootElement = updateRequest.getRootElement();

        Element templateIdElement = rootElement.element( "templateId" );
        templateIdElement.setText( readTemplateId );

        Element clientNameElement = rootElement.element( "clientName" );
        if ( clientNameElement != null )
        {
            clientNameElement.detach();
        }

        Element binaryAttachments = ( Element )rootElement.selectSingleNode( "//binaryAttachments" );
        if ( binaryAttachments != null )
        {
            binaryAttachments.add( originalBinaryAttachment );
        }

        Element clientRequestInitiationTimeElement = rootElement.element( "clientRequestInitiationTime" );
        if ( clientRequestInitiationTimeElement != null )
        {
            clientRequestInitiationTimeElement.detach();
        }

        /// detach all blobs 
        //        List<Node> nodes = rootElement.selectNodes("//hexBinaryAttachment");
        //        for ( Node node: nodes)
        //        {
        //        	node.detach();
        //        	node =null;
        //        }

        Element patient = ( Element )rootElement.selectSingleNode( "//patient" ).detach();

        //        Element requestIdElement = DocumentHelper.createElement("requestId");
        //        requestIdElement.setText(requestId);
        //        rootElement.add(requestIdElement);

        Element patientJournalEntries = ( Element )patient.selectSingleNode( "patientJournalEntries" ).detach();

        Element requestedEdiPi = DocumentHelper.createElement( "requestedEdiPi" );
        Element identity = DocumentHelper.createElement( "identity" );
        identity.setText( uniquePatientIdentity );
        requestedEdiPi.add( identity );
        Element assigningFacility = DocumentHelper.createElement( "assigningFacility" );
        assigningFacility.setText( "200DOD" );
        requestedEdiPi.add( assigningFacility );
        Element assigningAuthority = DocumentHelper.createElement( "assigningAuthority" );
        assigningAuthority.setText( "USDOD" );
        requestedEdiPi.add( assigningAuthority );

        Element resultantIdentifiers = DocumentHelper.createElement( "resultantIdentifiers" );
        Element resultantIdentifier = DocumentHelper.createElement( "resultantIdentifier" );
        resultantIdentifiers.add( resultantIdentifier );
        Element riIdentity = DocumentHelper.createElement( "identity" );
        riIdentity.setText( uniquePatientIdentity );
        resultantIdentifier.add( riIdentity );
        Element riAssigningFacility = DocumentHelper.createElement( "assigningFacility" );
        riAssigningFacility.setText( "200DOD" );
        resultantIdentifier.add( riAssigningFacility );
        Element riAssigningAuthority = DocumentHelper.createElement( "assigningAuthority" );
        riAssigningAuthority.setText( "USDOD" );
        resultantIdentifier.add( riAssigningAuthority );

        patient.add( requestedEdiPi );
        patient.add( resultantIdentifiers );
        patient.add( patientJournalEntries );

        Element patients = DocumentHelper.createElement( "patients" );
        patients.add( patient );
        rootElement.add( patients );
        return updateRequest;
    }


    @SuppressWarnings( "unchecked" )
    protected Document convertCreateRequestToExpectedJournalRead( String createRequestXml, String readTemplateId, String patientId,
                    boolean keepDetails )
        throws DocumentException
    {
        Document createRequest = DocumentHelper.parseText( createRequestXml );
        Element rootElement = createRequest.getRootElement();

        Element templateIdElement = rootElement.element( "templateId" );
        templateIdElement.setText( readTemplateId );

        Element clientNameElement = rootElement.element( "clientName" );
        if ( clientNameElement != null )
        {
            clientNameElement.detach();
        }

        Element clientRequestInitiationTimeElement = rootElement.element( "clientRequestInitiationTime" );
        if ( clientRequestInitiationTimeElement != null )
        {
            clientRequestInitiationTimeElement.detach();
        }
        if ( !keepDetails )
        {
            List<Node> nodesToDetach = rootElement.selectNodes( "//hexBinaryAttachment" );
            for ( Node node : nodesToDetach )
            {
                node.detach();
                node = null;
            }
            nodesToDetach = rootElement.selectNodes( "//base64BinaryAttachment" );
            for ( Node node : nodesToDetach )
            {
                node.detach();
            }

        }

        Element patient = ( Element )rootElement.selectSingleNode( "//patient" ).detach();

        Element patientJournalEntries = ( Element )patient.selectSingleNode( "patientJournalEntries" ).detach();

        Element requestedEdiPi = DocumentHelper.createElement( "requestedEdiPi" );
        Element identity = DocumentHelper.createElement( "identity" );
        identity.setText( patientId );
        requestedEdiPi.add( identity );
        Element assigningFacility = DocumentHelper.createElement( "assigningFacility" );
        assigningFacility.setText( "200DOD" );
        requestedEdiPi.add( assigningFacility );
        Element assigningAuthority = DocumentHelper.createElement( "assigningAuthority" );
        assigningAuthority.setText( "USDOD" );
        requestedEdiPi.add( assigningAuthority );

        Element resultantIdentifiers = DocumentHelper.createElement( "resultantIdentifiers" );
        Element resultantIdentifier = DocumentHelper.createElement( "resultantIdentifier" );
        resultantIdentifiers.add( resultantIdentifier );
        Element riIdentity = DocumentHelper.createElement( "identity" );
        riIdentity.setText( patientId );
        resultantIdentifier.add( riIdentity );
        Element riAssigningFacility = DocumentHelper.createElement( "assigningFacility" );
        riAssigningFacility.setText( "200DOD" );
        resultantIdentifier.add( riAssigningFacility );
        Element riAssigningAuthority = DocumentHelper.createElement( "assigningAuthority" );
        riAssigningAuthority.setText( "USDOD" );
        resultantIdentifier.add( riAssigningAuthority );

        patient.add( requestedEdiPi );
        patient.add( resultantIdentifiers );
        patient.add( patientJournalEntries );

        Element patients = DocumentHelper.createElement( "patients" );
        patients.add( patient );
        rootElement.add( patients );
        return createRequest;
    }


    protected String createDetailFilter( String filterId, Map<String, String> entryPointFilterMap, String clientRequestInitiationTime )
    {
        return dataGenerator.buildDetailFilterWithRecordIdentifier( filterId, entryPointFilterMap, clientRequestInitiationTime );
    }

}
