

package gov.va.med.cds.persistence.hibernate;


import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.common.person.correlation.PersonIdentifierInterface;
import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.persistence.QueryStrategyInterface;
import gov.va.med.cds.persistence.QueryWorkInterface;
import gov.va.med.cds.persistence.hibernate.common.PointInTimeUserType;
import gov.va.med.cds.rules.BooleanRuleInterface;
import gov.va.med.cds.template.generated.JaxBMarshallerUnmarshallerInterface;
import gov.va.med.cds.transaction.ReadWork;
import gov.va.med.cds.transaction.WorkManagerInterface;
import gov.va.med.cds.util.TimeoutUtil;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.easymock.EasyMock;
import org.hibernate.SessionFactory;
import org.junit.Assert;
import org.junit.Test;

import commonj.work.WorkItem;


public class DefaultHibernateReadPerstenceManagerTest
{

    @Test
    @Suite( groups = { "checkintest" } )
    public void testIsApplicableIsTrue( )
    {
        DefaultHibernateReadPersistenceManager persistenceManager = new DefaultHibernateReadPersistenceManager();

        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        BooleanRuleInterface rule1 = EasyMock.createMock( BooleanRuleInterface.class );
        BooleanRuleInterface rule2 = EasyMock.createMock( BooleanRuleInterface.class );
        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        PersonIdentifierInterface pid2 = EasyMock.createMock( PersonIdentifierInterface.class );

        EasyMock.expect( entryFilter.getDomainEntryPoint() ).andReturn( "AllergyAssessment" );
        EasyMock.expect( entryFilter.isPatientCentricFilter() ).andReturn( true );
        EasyMock.expect( entryFilter.isSiteCentricFilter() ).andReturn( false );
        EasyMock.expect( rule1.evaluate( DomainEntryPoint.AllergyAssessment ) ).andReturn( Boolean.FALSE );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "444" );
        EasyMock.expect( pid2.getAssigningFacility() ).andReturn( "555" );
        EasyMock.expect( rule2.evaluate( DomainEntryPoint.AllergyAssessment ) ).andReturn( Boolean.TRUE );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "444" );
        EasyMock.expect( pid2.getAssigningFacility() ).andReturn( "555" );

        EasyMock.replay( entryFilter, rule1, rule2, pid1, pid2 );

        List<BooleanRuleInterface> rules = new ArrayList<BooleanRuleInterface>();
        rules.add( rule1 );
        rules.add( rule2 );

        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        personIdentifiers.add( pid1 );
        personIdentifiers.add( pid2 );

        persistenceManager.setRules( rules );

        Assert.assertTrue( persistenceManager.isApplicable( entryFilter, personIdentifiers ) );
    }


    /*
     * The error conditions in this heirarchy of persistent hibernate read managers are covered in the
     * SiteSpecificHibernateReadManagerTest.
     */

    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "checkintest" } )
    public void testPerformReadOnClinicalData( )
        throws Exception
    {
        String templateId = "TestTemplateId";
        String entryPoint = "EntryPoint1";
        String requestId = "REQUEST-99999";
        String applicationName = "CDS";
        String siteId = "TestSiteId";

        DefaultHibernateReadPersistenceManager persistenceManager = new DefaultHibernateReadPersistenceManager();
        persistenceManager.setSiteIdentifier( siteId );
        persistenceManager.setPointInTimeUserType( PointInTimeUserType.class );
        List<PersonIdentifierInterface> personIdentifiers = new ArrayList<PersonIdentifierInterface>();
        Map<String, QueryStrategyInterface> queryStrategiesMap = new HashMap<String, QueryStrategyInterface>();
        List<QueryWorkInterface> queryWork = new ArrayList<QueryWorkInterface>();

        QueryWorkInterface work = createMock( QueryWorkInterface.class );
        expect( work.getExceptions() ).andReturn( new ArrayList<Exception>() );
        //TODO: we will need to remove the two lines below once the transaction fix is on place..SD
        work.release();
        expectLastCall();
        queryWork.add( work );

        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        expect( entryFilter.getTemplateId() ).andReturn( templateId ).anyTimes();
        expect( entryFilter.getDomainEntryPoint() ).andReturn( entryPoint ).anyTimes();
        expect( entryFilter.getRequestId() ).andReturn( requestId ).anyTimes();
        expect( entryFilter.getQueryName() ).andReturn( null ).anyTimes();

        expect( entryFilter.getTimeout() ).andReturn( null ).anyTimes();

        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        PersonIdentifierInterface pid2 = EasyMock.createMock( PersonIdentifierInterface.class );
        personIdentifiers.add( pid1 );
        personIdentifiers.add( pid2 );

        QueryStrategyInterface queryStrategy = EasyMock.createMock( QueryStrategyInterface.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        queryStrategiesMap.put( String.format( "%s-%s", templateId, entryPoint ), queryStrategy );
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = EasyMock.createMock( JaxBMarshallerUnmarshallerInterface.class );

        expect( pid1.getAssigningFacility() ).andReturn( "111" ).anyTimes();
        expect( pid2.getAssigningFacility() ).andReturn( "999" ).anyTimes();
        expect( pid1.getIdentity() ).andReturn( "111111" ).anyTimes();
        expect( pid2.getIdentity() ).andReturn( "999999" ).anyTimes();
        expect( queryStrategy.createQueryWork( EasyMock.eq( sessionFactory ), EasyMock.eq( entryFilter ), EasyMock.isA( List.class ),
        		EasyMock.eq( PointInTimeUserType.class ), EasyMock.eq( siteId ), EasyMock.eq(marshallerUnmarshaller) ) ).andReturn( queryWork );
        ModelAssemblerInterface modelAssembler = EasyMock.createMock( ModelAssemblerInterface.class );
        expect( modelAssembler.assembleModel( entryFilter, queryWork ) ).andReturn( DocumentHelper.createDocument() );
        expect( queryStrategy.getModelAssembler() ).andReturn( modelAssembler );

        Map<String, String> templateTimeoutMap = new HashMap<String, String>();
        templateTimeoutMap.put( TimeoutUtil.UPPER_LIMIT_TIMEOUT, "300" );

        WorkManagerInterface workManager = EasyMock.createMock( WorkManagerInterface.class );
        WorkItem workItem1 = EasyMock.createMock( WorkItem.class );
        EasyMock.expect( workManager.schedule( ( ( ReadWork )EasyMock.anyObject() ) ) ).andReturn( workItem1 );
        EasyMock.expect( workManager.waitForAll( ( ( List<WorkItem> )EasyMock.anyObject() ), EasyMock.eq( 300000L ) ) ).andReturn( true ).anyTimes();

        persistenceManager.setTemplateTimeoutMap( templateTimeoutMap );
        persistenceManager.setQueryThreadWorkManager( workManager );
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);

        EasyMock.replay( entryFilter, queryStrategy, pid1, pid2, modelAssembler, work, workManager );

        persistenceManager.setTemplateQueryStrategyMap( queryStrategiesMap );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );

        Document result = persistenceManager.performReadOnClinicalData( entryFilter, personIdentifiers, applicationName );

        Assert.assertNotNull( result );
    }
}
