/**
 * 
 */


package gov.va.med.cds.transaction;


import gov.va.med.cds.AbstractBaseUnitCoreTest;
import gov.va.med.cds.clinicaldata.DomainClinicalRecordElementHelper;
import gov.va.med.cds.clinicaldata.DomainClinicalRecordElementHelperInterface;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.clinicaldata.Operation;
import gov.va.med.cds.common.person.correlation.PersonIdentifierInterface;
import gov.va.med.cds.filter.CdsFilterInterface;
import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.persistence.PersistenceException;
import gov.va.med.cds.persistence.PersistenceLocatorInterface;
import gov.va.med.cds.persistence.ReadPersistenceManagerInterface;
import gov.va.med.cds.persistence.WritePersistenceManagerInterface;
import gov.va.med.cds.response.WriteResponseGeneratorInterface;
import gov.va.med.cds.template.TemplateHelperInterface;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import commonj.work.WorkItem;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * @author vhaislegberb
 *
 */
@RunWith( SuiteAwareRunner.class )
public class DefaultTransactionManagerTest
    extends
        AbstractBaseUnitCoreTest
{

    @Test
    @Suite( groups = { "brokentest" } )
    public void testPerformReadOnClinicalDataFilterOnly( )
        throws Exception
    {
        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        List<EntryFilterInterface> entryFilters = new ArrayList<EntryFilterInterface>();
        List<ReadPersistenceManagerInterface> readPersistenceManagers = new ArrayList<ReadPersistenceManagerInterface>();
        List<String> validNonVistaSites = new ArrayList();
        validNonVistaSites.add( "200CH" );
        validNonVistaSites.add( "200HD" );

        CdsFilterInterface filter = EasyMock.createMock( CdsFilterInterface.class );
        PersistenceLocatorInterface persistenceLocator = EasyMock.createMock( PersistenceLocatorInterface.class );
        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        PersonIdentifierInterface pid2 = EasyMock.createMock( PersonIdentifierInterface.class );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "508" );
        EasyMock.expect( pid2.getAssigningFacility() ).andReturn( "509" );

        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        ReadPersistenceManagerInterface rpm1 = EasyMock.createMock( ReadPersistenceManagerInterface.class );
        ReadPersistenceManagerInterface rpm2 = EasyMock.createMock( ReadPersistenceManagerInterface.class );
        EasyMock.expect( rpm1.getSiteIdentifier() ).andReturn( "508" );
        EasyMock.expect( rpm2.getSiteIdentifier() ).andReturn( "509" );

        WorkManagerInterface workManager = EasyMock.createMock( WorkManagerInterface.class );
        WorkItem workItem1 = EasyMock.createMock( WorkItem.class );
        WorkItem workItem2 = EasyMock.createMock( WorkItem.class );

        ReadWork readWork1 = new ReadWork( rpm1, entryFilter, personIdentifiers );
        ReadWork readWork2 = new ReadWork( rpm2, entryFilter, personIdentifiers );

        personIdentifiers.add( pid1 );
        personIdentifiers.add( pid2 );

        entryFilters.add( entryFilter );

        readPersistenceManagers.add( rpm1 );
        readPersistenceManagers.add( rpm2 );

        EasyMock.expect( filter.getPersonIdentifiers() ).andReturn( personIdentifiers );
        EasyMock.expect( filter.getEntryPointFilters() ).andReturn( entryFilters );
        EasyMock.expect( persistenceLocator.getReadPersistenceManagers( entryFilter, personIdentifiers ) ).andReturn( readPersistenceManagers );
        EasyMock.expect( workManager.schedule( ( ( ReadWork )EasyMock.anyObject() ) ) ).andReturn( workItem1 );
        EasyMock.expect( workManager.schedule( ( ( ReadWork )EasyMock.anyObject() ) ) ).andReturn( workItem2 );
        EasyMock.expect( workManager.waitForAll( ( ( List<WorkItem> )EasyMock.anyObject() ) ) ).andReturn( true ).anyTimes();
        EasyMock.expect( workItem1.getResult() ).andReturn( readWork1 );
        EasyMock.expect( entryFilter.getXpathQuery() ).andReturn( null );
        EasyMock.expect( filter.isPatientCentricFilter() ).andReturn( true );
        EasyMock.expect( workItem2.getResult() ).andReturn( readWork2 );
        EasyMock.expect( entryFilter.getXpathQuery() ).andReturn( "" );
        EasyMock.expect( filter.getNationalId() ).andReturn( null );
        
        TemplateHelperInterface templateHelper = EasyMock.createNiceMock( TemplateHelperInterface.class );
        EasyMock.expect( templateHelper.getApplicationName("templateId") ).andReturn("CDS 3.5").anyTimes();
            
        EasyMock.replay( filter, persistenceLocator, templateHelper, pid1, pid2, entryFilter, rpm1, rpm2, workManager, workItem1, workItem2 );

        DefaultTransactionManager txnMgr = new DefaultTransactionManager();
        txnMgr.setPersistenceLocator( persistenceLocator );
        txnMgr.setWorkManager( workManager );
        txnMgr.setValidNonVistaSites( validNonVistaSites );
        txnMgr.setTemplateHelper(templateHelper);
        List<Document> results = txnMgr.performReadOnClinicalData( filter );
        Assert.assertNotNull( results );

        EasyMock.verify( filter, persistenceLocator, templateHelper, pid1, pid2, entryFilter, rpm1, rpm2, workManager, workItem1, workItem2 );
    }


    @Test
    @Suite( groups = { "brokentest" } )
    public void testPerformCUADOnClinicalData( )
        throws Exception
    {
        //in order to avoid a nullpointer will need a basic document with some minimal high level elements set.
        String templateId = "AllergyAssessmentCreateOrUpdate40060";
        String requestId = "123";
        String domainEntryPoint = "domainEntryPoint";
        Document clinicalDataDocument = buildClinicalDataDocument( "AllergyAssessmentCreateOrUpdate40060", null, true );
        List<String> validNonVistaSites = new ArrayList();
        validNonVistaSites.add( "200CH" );
        validNonVistaSites.add( "200HD" );

        Map<String, Set<DomainEntryPoint>> templateIdToDomainEntryPointListMap = new HashMap<String, Set<DomainEntryPoint>>();
        Set<DomainEntryPoint> domainEntryPoints = new HashSet<DomainEntryPoint>();
        domainEntryPoints.add( DomainEntryPoint.AllergyAssessment );
        templateIdToDomainEntryPointListMap.put( templateId, domainEntryPoints );

        PersistenceLocatorInterface persistenceLocator = EasyMock.createNiceMock( PersistenceLocatorInterface.class );
        WritePersistenceManagerInterface wpm = EasyMock.createNiceMock( WritePersistenceManagerInterface.class );

        EasyMock.expect( persistenceLocator.getWritePersistenceManager( DomainEntryPoint.AllergyAssessment ) ).andReturn( wpm );
        //in order to verify mocks - will need to add assessment element to document as it will be pulled out and given to proxy to fulfill line 120
        Element clinicalRecord = DocumentHelper.createElement( "allergyAssessments" );
        clinicalDataDocument.getRootElement().element( "patient" ).add( clinicalRecord );

        TemplateHelperInterface templateHelper = EasyMock.createNiceMock( TemplateHelperInterface.class );
        EasyMock.expect( templateHelper.getApplicationName("templateId") ).andReturn("CDS 3.5").anyTimes();
  
        WriteResponseGeneratorInterface writeResponseGeneratorInterface = EasyMock.createNiceMock( WriteResponseGeneratorInterface.class );

        EasyMock.expect( templateHelper.getWriteResponseGenerator( EasyMock.isA( String.class ) ) ).andReturn( writeResponseGeneratorInterface ).anyTimes();

        EasyMock.replay( persistenceLocator, wpm, templateHelper );

        wpm.performCUADOnClinicalData( templateId, Operation.Create, clinicalRecord, DomainEntryPoint.AllergyAssessment );

        DefaultTransactionManager txnMgr = new DefaultTransactionManager();

        Map<String, String> templateTimeoutMap = new HashMap<String, String>();
        templateTimeoutMap.put( "upperLimitTimeout", "5" );

        Map<String, DomainClinicalRecordElementHelperInterface> domainClinicalRecordOwnerMap = new HashMap<String, DomainClinicalRecordElementHelperInterface>();

        DomainClinicalRecordElementHelper domainClinicalRecordElementHelper = new DomainClinicalRecordElementHelper();
        domainClinicalRecordElementHelper.setAuthorityOwner( "patient.identifier.assigningAuthority" );
        domainClinicalRecordElementHelper.setDomainIdentityOwner( "recordIdentifier.identity" );
        domainClinicalRecordElementHelper.setFacilityOwner( "patient.identifier.assigningFacility" );

        domainClinicalRecordOwnerMap.put( "defaultDomainOwner", domainClinicalRecordElementHelper );

        txnMgr.setTemplateHelper( templateHelper );
        txnMgr.setDomainClinicalRecordOwnerMap( domainClinicalRecordOwnerMap );
        txnMgr.setTemplateTimeoutMap( templateTimeoutMap );
        txnMgr.setPersistenceLocator( persistenceLocator );
        txnMgr.setTemplateIdToDomainEntryPointListMap( templateIdToDomainEntryPointListMap );
        txnMgr.setValidNonVistaSites( validNonVistaSites );
        txnMgr.performCUADOnClinicalData( Operation.Create, clinicalDataDocument, templateId, requestId );
        EasyMock.verify( persistenceLocator, wpm );
    }


    @Test
    @Suite( groups = { "brokentest" } )
    public void testReadWorkLifecycle( )
        throws Exception
    {
        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        Document clinicalDataDocument = DocumentHelper.createDocument();

        ReadPersistenceManagerInterface persistenceManager = EasyMock.createMock( ReadPersistenceManagerInterface.class );
        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );

        String applicationName = "CDS";

        EasyMock.expect( persistenceManager.performReadOnClinicalData( entryFilter, personIdentifiers, applicationName ) ).andReturn( clinicalDataDocument );

        EasyMock.replay( persistenceManager, entryFilter );

        ReadWork readWork = new ReadWork( persistenceManager, entryFilter, personIdentifiers );
        readWork.setCdsAppName( applicationName );
        Assert.assertFalse( readWork.isDaemon() );
        readWork.run();
        readWork.release();
        Assert.assertEquals( readWork.getResult(), clinicalDataDocument );

        EasyMock.verify( persistenceManager, entryFilter );
    }


    @Test
    @Suite( groups = { "brokentest" } )
    public void testPerformReadOnClinicalDataFilterWithXPath( )
        throws Exception
    {
        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        List<EntryFilterInterface> entryFilters = new ArrayList<EntryFilterInterface>();
        List<ReadPersistenceManagerInterface> readPersistenceManagers = new ArrayList<ReadPersistenceManagerInterface>();
        List<String> validNonVistaSites = new ArrayList();
        validNonVistaSites.add( "200CH" );
        validNonVistaSites.add( "200HD" );

        // Create Mocks
        CdsFilterInterface filter = EasyMock.createMock( CdsFilterInterface.class );
        PersistenceLocatorInterface persistenceLocator = EasyMock.createMock( PersistenceLocatorInterface.class );
        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "508" );

        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        ReadPersistenceManagerInterface rpm = EasyMock.createMock( ReadPersistenceManagerInterface.class );
        EasyMock.expect( rpm.getSiteIdentifier() ).andReturn( "508" );

        WorkManagerInterface workManager = EasyMock.createMock( WorkManagerInterface.class );
        WorkItem workItem = EasyMock.createMock( WorkItem.class );

        // Set Mocks to read work
        personIdentifiers.add( pid1 );
        entryFilters.add( entryFilter );
        readPersistenceManagers.add( rpm );
        ReadWork readWork = new ReadWork( rpm, entryFilter, personIdentifiers );

        // Build document stub with two allergyAssesments and set it to read work
        Document result = buildClinicalDataDocument();
        Element patient = DocumentHelper.createElement( "patient" );
        patient.addElement( "allergyAssessments" ).addElement( "status" ).addText( "A" );
        patient.addElement( "allergyAssessments" ).addElement( "status" ).addText( "E" );
        result.getRootElement().add( patient );
        readWork.setResult( result );

        // Set expectations
        EasyMock.expect( filter.getPersonIdentifiers() ).andReturn( personIdentifiers );
        EasyMock.expect( filter.getEntryPointFilters() ).andReturn( entryFilters );
        EasyMock.expect( persistenceLocator.getReadPersistenceManagers( entryFilter, personIdentifiers ) ).andReturn( readPersistenceManagers );
        EasyMock.expect( workManager.schedule( ( ( ReadWork )EasyMock.anyObject() ) ) ).andReturn( workItem );
        EasyMock.expect( workManager.waitForAll( ( ( List<WorkItem> )EasyMock.anyObject() ) ) ).andReturn( true ).anyTimes();
        EasyMock.expect( workItem.getResult() ).andReturn( readWork );
        EasyMock.expect( entryFilter.getXpathQuery() ).andReturn( "allergyAssessments[status != 'E']" );
        EasyMock.expect( filter.isPatientCentricFilter() ).andReturn( true );
        EasyMock.expect( filter.getNationalId() ).andReturn( null );

        TemplateHelperInterface templateHelper = EasyMock.createNiceMock( TemplateHelperInterface.class );
        EasyMock.expect( templateHelper.getApplicationName("templateId") ).andReturn("CDS 3.5").anyTimes();
   
        EasyMock.replay( filter, persistenceLocator, templateHelper, pid1, entryFilter, rpm, workManager, workItem );

        DefaultTransactionManager txnMgr = new DefaultTransactionManager();
        txnMgr.setPersistenceLocator( persistenceLocator );
        txnMgr.setWorkManager( workManager );
        txnMgr.setValidNonVistaSites( validNonVistaSites );
        txnMgr.setTemplateHelper(templateHelper);

        // Execute performReadOnClinicalData
        List<Document> results = txnMgr.performReadOnClinicalData( filter );

        Assert.assertNotNull( results );
        Assert.assertTrue( results.get( 0 ).selectNodes( "//allergyAssessments" ).size() == 1 );
        Assert.assertTrue( results.get( 0 ).selectNodes( "//allergyAssessments[status = 'E']" ).size() == 0 );
        Assert.assertTrue( results.get( 0 ).selectNodes( "//allergyAssessments[status = 'A']" ).size() == 1 );

        EasyMock.verify( filter, persistenceLocator, templateHelper, pid1, entryFilter, rpm, workManager, workItem );
    }


    @Test
    @Suite( groups = { "brokentest" } )
    public void testPerformReadOnClinicalDataFilterWithXPath_AllRecordsFilteredOut( )
        throws Exception
    {
        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        List<EntryFilterInterface> entryFilters = new ArrayList<EntryFilterInterface>();
        List<ReadPersistenceManagerInterface> readPersistenceManagers = new ArrayList<ReadPersistenceManagerInterface>();
        List<String> validNonVistaSites = new ArrayList();
        validNonVistaSites.add( "200CH" );
        validNonVistaSites.add( "200HD" );

        // Create Mocks
        CdsFilterInterface filter = EasyMock.createMock( CdsFilterInterface.class );
        PersistenceLocatorInterface persistenceLocator = EasyMock.createMock( PersistenceLocatorInterface.class );
        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "508" );

        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        ReadPersistenceManagerInterface rpm = EasyMock.createMock( ReadPersistenceManagerInterface.class );
        EasyMock.expect( rpm.getSiteIdentifier() ).andReturn( "508" );

        WorkManagerInterface workManager = EasyMock.createMock( WorkManagerInterface.class );
        WorkItem workItem = EasyMock.createMock( WorkItem.class );

        // Set Mocks to read work
        personIdentifiers.add( pid1 );
        entryFilters.add( entryFilter );
        readPersistenceManagers.add( rpm );
        ReadWork readWork = new ReadWork( rpm, entryFilter, personIdentifiers );

        // Build document stub with two allergyAssesments and set it to read work
        Document result = buildClinicalDataDocument();
        Element patient = DocumentHelper.createElement( "patient" );
        patient.addElement( "allergyAssessments" ).addElement( "status" ).addText( "E" );
        patient.addElement( "allergyAssessments" ).addElement( "status" ).addText( "E" );
        result.getRootElement().add( patient );
        readWork.setResult( result );

        // Set expectations
        EasyMock.expect( filter.getPersonIdentifiers() ).andReturn( personIdentifiers );
        EasyMock.expect( filter.getEntryPointFilters() ).andReturn( entryFilters );
        EasyMock.expect( persistenceLocator.getReadPersistenceManagers( entryFilter, personIdentifiers ) ).andReturn( readPersistenceManagers );
        EasyMock.expect( workManager.schedule( ( ( ReadWork )EasyMock.anyObject() ) ) ).andReturn( workItem );
        EasyMock.expect( workManager.waitForAll( ( ( List<WorkItem> )EasyMock.anyObject() ) ) ).andReturn( true ).anyTimes();
        EasyMock.expect( workItem.getResult() ).andReturn( readWork );
        EasyMock.expect( entryFilter.getXpathQuery() ).andReturn( "allergyAssessments[status != 'E']" );
        EasyMock.expect( filter.isPatientCentricFilter() ).andReturn( true );
        EasyMock.expect( filter.getNationalId() ).andReturn( null );

        TemplateHelperInterface templateHelper = EasyMock.createNiceMock( TemplateHelperInterface.class );
        EasyMock.expect( templateHelper.getApplicationName("templateId") ).andReturn("CDS 3.5").anyTimes();
     
        EasyMock.replay( filter, persistenceLocator, templateHelper, pid1, entryFilter, rpm, workManager, workItem );

        DefaultTransactionManager txnMgr = new DefaultTransactionManager();
        txnMgr.setPersistenceLocator( persistenceLocator );
        txnMgr.setWorkManager( workManager );
        txnMgr.setValidNonVistaSites( validNonVistaSites );
        txnMgr.setTemplateHelper(templateHelper);

        // Execute performReadOnClinicalData
        List<Document> results = txnMgr.performReadOnClinicalData( filter );

        Assert.assertNotNull( results );
        Assert.assertTrue( results.get( 0 ).selectNodes( "//patient" ).size() == 1 );
        Assert.assertTrue( results.get( 0 ).selectNodes( "//allergyAssessments" ).size() == 0 );

        EasyMock.verify( filter, persistenceLocator, templateHelper, pid1, entryFilter, rpm, workManager, workItem );
    }

}
