/**
 * 
 */


package gov.va.med.cds.response;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.clinicaldata.vhim400.ClinicalDataResponse400;
import gov.va.med.cds.clinicaldata.vhim400.ClinicalDataResponseInterface;
import gov.va.med.cds.filter.CdsFilterFactoryInterface;
import gov.va.med.cds.filter.CdsFilterInterface;
import gov.va.med.cds.filter.DefaultCdsFilterFactory;
import gov.va.med.cds.filter.EntryFilterFactory;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;

import java.util.List;

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


/**
 * @author DNS   TALBOM
 *
 * Test Class will test all implementations of the <PatientIdentifierDocumentBuilderInterface>
 * 
 */
@RunWith( SuiteAwareRunner.class )
public class PatientIdentifierDocumentBuilderTest
{

    protected Document filterWithNationalId = null;
    protected Document filterWithLocalId = null;
    protected Document filterWithNationalIdAndExcluded = null;
    protected Document filterWithNationalIdAndExcludedNoIdentity = null;
    protected Document filterWithLocalIdAndExcluded = null;
    protected String templateId = TemplateIdHelper.INTOLERANCE_CONDITION_READ_TEMPLATE_ID;
    protected String requestId = TemplateIdHelper.UNIQUE_REQUEST_ID;
    protected String filterId = "IC_SINGLE_PATIENT_ALL_DATA_FILTER";
    protected CdsFilterFactoryInterface filterFactory = new DefaultCdsFilterFactory();
    protected ClinicalDataResponseInterface clinicalDataResponse = new ClinicalDataResponse400();
    
    
    @Before
    public void setup()
    {
        ((DefaultCdsFilterFactory)this.filterFactory).setEntryFilterFactory( new EntryFilterFactory() );
    }



    /**
     * Test method will test a Sequenced Document type or older Vhim versions
     */
    @Test
    @Suite( groups = { "checkintest" } )
    public void testSequenceCreatePatientWithIdentifiersDocumentTest( )
    {
        DefaultPatientIdentifierDocumentBuilder identifierBuilder = new DefaultPatientIdentifierDocumentBuilder();
        identifierBuilder.setClinicalDataResponse( clinicalDataResponse );
       
        //test each of 4 combinations
        //local only
        CdsFilterInterface filter = filterFactory.create( filterId, filterWithLocalId, templateId, requestId );
        Document document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        Element rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        Element patient = rootElement.element( "patient" );
        List<Element> identifiers = patient.elements( "requestedResolvedIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        identifiers = patient.elements( "resultantIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        
        
        //local with excludes
        filter = filterFactory.create( filterId, filterWithLocalIdAndExcluded, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        identifiers = patient.elements( "requestedResolvedIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        identifiers = patient.elements( "resultantIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        List<Element> excluded = patient.elements( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        assertTrue(excluded.size()==1);
        
        //national only
        filter = filterFactory.create( filterId, filterWithNationalId, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        Element nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.elements( "resultantIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        
        //national with excludes
        filter = filterFactory.create( filterId, filterWithNationalIdAndExcluded, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.elements( "resultantIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        excluded = patient.elements( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        assertTrue(excluded.size()==1);
        
        //national with excludes, no identity
        filter = filterFactory.create( filterId, filterWithNationalIdAndExcludedNoIdentity, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.elements( "resultantIdentifiers" );
        assertNotNull(identifiers);
        assertTrue(identifiers.size()==1);
        excluded = patient.elements( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        assertTrue(excluded.size()==1);
    }


    /**
     * Test method will test a Non-Sequenced Document type such as TIU
     */
    @Test
    @Suite( groups = { "checkintest" } )
    public void testNonSequenceCreatePatientWithIdentifiersDocumentTest( )
    {
        NonSequencePatientIdentifierDocumentBuilder identifierBuilder = new NonSequencePatientIdentifierDocumentBuilder();
        identifierBuilder.setClinicalDataResponse( clinicalDataResponse );
        
        //test each of 4 combinations
        //local only
        CdsFilterInterface filter = filterFactory.create( filterId, filterWithLocalId, templateId, requestId );
        Document document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        Element rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        Element patient = rootElement.element( "patient" );
        Element identifiers = patient.element( "requestedResolvedIdentifiers" );
        assertNotNull(identifiers);
        List<Element> identifier = identifiers.elements( "requestedResolvedIdentifier" );
        assertNotNull(identifier);
        assertTrue(identifier.size()==1);
        
        //local with excludes
        filter = filterFactory.create( filterId, filterWithLocalIdAndExcluded, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        identifiers = patient.element( "requestedResolvedIdentifiers" );
        assertNotNull(identifiers);
        identifier = identifiers.elements( "requestedResolvedIdentifier" );
        assertNotNull(identifier);
        assertTrue(identifier.size()==1);
        Element excluded = patient.element( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        List<Element> excludes = excluded.elements( "requestedExcludedIdentifier");
        assertNotNull(excludes);
        assertTrue(excludes.size()==1);
        
        //national only
        filter = filterFactory.create( filterId, filterWithNationalId, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        Element nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.element( "resultantIdentifiers" );
        assertNotNull(identifiers);
        identifier = identifiers.elements( "resultantIdentifier" );
        assertNotNull(identifier);
        assertTrue(identifier.size()==1);
        
        //national with excludes
        filter = filterFactory.create( filterId, filterWithNationalIdAndExcluded, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.element( "resultantIdentifiers" );
        assertNotNull(identifiers);
        identifier = identifiers.elements( "resultantIdentifier" );
        assertNotNull(identifier);
        assertTrue(identifier.size()==1);
        excluded = patient.element( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        excludes = excluded.elements( "requestedExcludedIdentifier");
        assertNotNull(excludes);
        assertTrue(excludes.size()==1);

        //national with excludes, no identity
        filter = filterFactory.create( filterId, filterWithNationalIdAndExcludedNoIdentity, templateId, requestId );
        document = identifierBuilder.createPatientWithIdentifiersDocument( filter, templateId, requestId);
        assertNotNull(document);
        rootElement = document.getRootElement();
        assertEquals(rootElement.elementText( "templateId" ), templateId);
        assertEquals(rootElement.elementText( "requestId"), requestId );
        patient = rootElement.element( "patient" );
        nationalId = patient.element( "requestedNationalId" );
        assertNotNull(nationalId);
        identifiers = patient.element( "resultantIdentifiers" );
        assertNotNull(identifiers);
        identifier = identifiers.elements( "resultantIdentifier" );
        assertNotNull(identifier);
        assertTrue(identifier.size()==1);
        excluded = patient.element( "requestedExcludedIdentifiers");
        assertNotNull(excluded);
        excludes = excluded.elements( "requestedExcludedIdentifier");
        assertNotNull(excludes);
        assertTrue(excludes.size()==1);
    }


    @Before
    @Suite( groups = { "checkintest" } )
    public void setUp( )
        throws Exception
    {
        //create an entryPointFilter element each filter can use
        Element entryPointFilter = DocumentHelper.createElement( "entryPointFilter" );
        DocumentHelper.createAttribute( entryPointFilter, "queryName", "FilterQuery" );
        entryPointFilter.addElement( "domainEntryPoint" ).setText( "IntolernaceCondition" );
                
        //instantiate 4 filter documents so each test method can instantiate a cdsFilter ...  
        //local only
        filterWithLocalId = DocumentHelper.createDocument( DocumentHelper.createElement( "clinicalData" ));
        Element rootElement1 = filterWithLocalId.getRootElement();
        rootElement1.addElement( "filterId" ).setText( filterId );
        Element patients1 = DocumentHelper.createElement( "patients" );
        patients1.add( createIdentifiersElement("resolvedIdentifiers", "localId", "localAuthority", "localFacility") );
        rootElement1.add((Element)entryPointFilter.clone());
        rootElement1.add( patients1 );
        
        //local and exclude
        filterWithLocalIdAndExcluded = DocumentHelper.createDocument( DocumentHelper.createElement( "clinicalData" ));
        Element rootElement2 = filterWithLocalIdAndExcluded.getRootElement();
        rootElement2.addElement( "filterId" ).setText( filterId );
        Element patients2 = DocumentHelper.createElement( "patients" );
        patients2.add( createIdentifiersElement("resolvedIdentifiers", "localId", "localAuthority", "localFacility") );
        patients2.add( createIdentifiersElement("excludeIdentifiers", "localId", "localAuthority", "localFacility") );
        rootElement2.add((Element)entryPointFilter.clone());
        rootElement2.add( patients2 );

        //national only
        filterWithNationalId = DocumentHelper.createDocument( DocumentHelper.createElement( "clinicalData" ));
        Element rootElement3 = filterWithNationalId.getRootElement();
        rootElement3.addElement( "filterId" ).setText( filterId );
        Element patients3 = DocumentHelper.createElement( "patients" );
        patients3.addElement( "NationalId" ).setText( "nationalId" );
        patients3.add( createIdentifiersElement("resolvedIdentifiers", "localId", "localAuthority", "localFacility") );
        rootElement3.add((Element)entryPointFilter.clone());
        rootElement3.add( patients3 );
        
        //national with exclude
        filterWithNationalIdAndExcluded = DocumentHelper.createDocument( DocumentHelper.createElement( "clinicalData" ));
        Element rootElement4 = filterWithNationalIdAndExcluded.getRootElement();
        rootElement4.addElement( "filterId" ).setText( filterId );
        Element patients4 = DocumentHelper.createElement( "patients" );
        patients4.addElement( "NationalId" ).setText( "nationalId" );
        patients4.add( createIdentifiersElement("resolvedIdentifiers", "localSite1Id", "localSite1Authority", "localSite1Facility") );
        patients4.add( createIdentifiersElement("excludeIdentifiers", "localSite2Id", "localSite2Authority", "localSite2Facility") );
        rootElement4.add((Element)entryPointFilter.clone());
        rootElement4.add( patients4 );
        
        //national with exclude, no identity
        filterWithNationalIdAndExcludedNoIdentity = DocumentHelper.createDocument( DocumentHelper.createElement( "clinicalData" ));
        Element rootElement5 = filterWithNationalIdAndExcludedNoIdentity.getRootElement();
        rootElement5.addElement( "filterId" ).setText( filterId );
        Element patients5 = DocumentHelper.createElement( "patients" );
        patients5.addElement( "NationalId" ).setText( "nationalId" );
        patients5.add( createIdentifiersElement("resolvedIdentifiers", "", "localSite1Authority", "localSite1Facility") );
        patients5.add( createIdentifiersElement("excludeIdentifiers", "", "localSite2Authority", "localSite2Facility") );
        rootElement5.add((Element)entryPointFilter.clone());
        rootElement5.add( patients5 );
    }


    protected Element createIdentifiersElement(String elementName, String identity, String authority, String facility )
    {
        Element identifiers = DocumentHelper.createElement( elementName );
        identifiers.addElement( "identity" ).setText( identity );
        identifiers.addElement( "assigningAuthority" ).setText( authority );
        identifiers.addElement( "assigningFacility" ).setText( facility );
        return identifiers;
    }

}
