/**
 * 
 */


package gov.va.med.cds.integration.transaction;


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.filter.ParameterMapInterface;
import gov.va.med.cds.filter.QueryParameter;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.testharness.AbstractBaseTest;
import gov.va.med.cds.transaction.TransactionManagerInterface;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.easymock.EasyMock;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;


@RunWith( SuiteAwareSpringRunner.class )
@ContextConfiguration( locations = { "classpath:gov/va/med/cds/config/nonWeblogicHdr2DataSourceContext.xml",
                "classpath:gov/va/med/cds/config/hdr2PersistenceContext.xml",
                "classpath:gov/va/med/cds/config/hdr2PersistenceSessionFactoriesContext.xml",
                "classpath:gov/va/med/cds/config/vistaPersistenceContext.xml",
                "classpath:gov/va/med/cds/config/nonWeblogicVistaDataSourceContext.xml", "classpath:gov/va/med/cds/config/transactionContext.xml" } )
/***
 * DefaultTransactionManagerTest executes named queries in Hibernate mapping files. Successful execution of named queries
 * verifies basic accuracy of hbm.xml file setup.  
 */
public class DefaultTransactionManagerTest
    extends
        AbstractBaseTest
{
    private Log logger = LogFactory.getLog( DefaultTransactionManagerTest.class );

    @Resource
    private TransactionManagerInterface transactionManager;

    @Resource
    private SessionFactory vista662TiuRead40012SessionFactory;

    @Resource
    private SessionFactory hdr2VitalsignsRead40010SessionFactory;

    @Resource
    private SessionFactory hdr2VitalsignsDelete40030SessionFactory;

    @Resource
    private SessionFactory hdr2VitalsignsCreate40020SessionFactory;

    @Resource
    private SessionFactory hdr2VitalsignsCreateOrUpdate40060SessionFactory;

    @Resource
    private SessionFactory hdr2VWVitalsignsRead40010SessionFactory;

    @Resource
    private SessionFactory hdr2VWAllergiesRead40010SessionFactory;

    @Resource
    private SessionFactory hdr2VWIntoleranceConditionRead40010SessionFactory;

    @Resource
    private SessionFactory hdr2VWPharmacyDetailRead40010SessionFactory;

    @Resource
    private SessionFactory hdr2VWPharmacyRead40010SessionFactory;


    public void setHdr2VitalsignsRead40010SessionFactory( SessionFactory hdr2VitalsignsRead40010SessionFactory )
    {
        this.hdr2VitalsignsRead40010SessionFactory = hdr2VitalsignsRead40010SessionFactory;
    }

    public void setHdr2VitalsignsDelete40030SessionFactory( SessionFactory hdr2VitalsignsDelete40030SessionFactory )
    {
        this.hdr2VitalsignsDelete40030SessionFactory = hdr2VitalsignsDelete40030SessionFactory;
    }


    public void setHdr2VitalsignsCreate40020SessionFactory( SessionFactory hdr2VitalsignsCreate40020SessionFactory )
    {
        this.hdr2VitalsignsCreate40020SessionFactory = hdr2VitalsignsCreate40020SessionFactory;
    }


    public void setHdr2VitalsignsCreateOrUpdate40060SessionFactory( SessionFactory hdr2VitalsignsCreateOrUpdate40060SessionFactory )
    {
        this.hdr2VitalsignsCreateOrUpdate40060SessionFactory = hdr2VitalsignsCreateOrUpdate40060SessionFactory;
    }


    public void setHdr2VWVitalsignsRead40010SessionFactory( SessionFactory hdr2vwVitalsignsRead40010SessionFactory )
    {
        hdr2VWVitalsignsRead40010SessionFactory = hdr2vwVitalsignsRead40010SessionFactory;
    }


    public void setHdr2VWAllergiesRead40010SessionFactory( SessionFactory hdr2vwAllergiesRead40010SessionFactory )
    {
        this.hdr2VWAllergiesRead40010SessionFactory = hdr2vwAllergiesRead40010SessionFactory;
    }


    public void setHdr2VWIntoleranceConditionRead40010SessionFactory( SessionFactory hdr2vwIntoleranceConditionRead40010SessionFactory )
    {
        this.hdr2VWIntoleranceConditionRead40010SessionFactory = hdr2vwIntoleranceConditionRead40010SessionFactory;
    }


    public void setHdr2VWPharmacyDetailRead40010SessionFactory( SessionFactory hdr2vwPharmacyDetailRead40010SessionFactory )
    {
        this.hdr2VWPharmacyDetailRead40010SessionFactory = hdr2vwPharmacyDetailRead40010SessionFactory;
    }


    public void setHdr2VWPharmacyRead40010SessionFactory( SessionFactory hdr2vwPharmacyRead40010SessionFactory )
    {
        this.hdr2VWPharmacyRead40010SessionFactory = hdr2vwPharmacyRead40010SessionFactory;
    }


    private void executeNamedQuery( String namedQuery, SessionFactory sessionFactory, List<String> pids, List<String> recordIdentifiers,
                    String startDate, String endDate, String opmpId )
    {
        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "namedQuery : " + namedQuery );
        }

        //Session session = sessionFactory.openSession().getSession( );
        Session session = sessionFactory.openSession();

        Query queryByParameters = session.getNamedQuery( namedQuery );

        if ( null != pids )
        {
            queryByParameters.setParameterList( "pids", pids );
        }

        if ( null != recordIdentifiers )
        {
            queryByParameters.setParameterList( "recordIdentifiers", recordIdentifiers );
        }

        if ( null != startDate )
        {
            queryByParameters.setParameter( "startDate", startDate );
        }

        if ( null != endDate )
        {
            queryByParameters.setParameter( "endDate", endDate );
        }

        if ( null != opmpId )
        {
            queryByParameters.setParameter( "opmpId", opmpId );
        }

        List results = queryByParameters.list();

        for ( Object obj : results )
        {
            if ( obj instanceof DefaultElement )
            {
                DefaultElement e = ( DefaultElement )obj;

                if ( logger.isDebugEnabled() )
                {
                    logger.debug( namedQuery + '\n' + e.asXML() + '\n' );
                }
            }

        }
    }


    //TODO: Remove method after fixing date issue
    private void executeNamedQuery( String namedQuery, SessionFactory sessionFactory, List<String> pids, List<String> recordIdentifiers,
                    Element startDate, Element endDate )
    {
        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "namedQuery : " + namedQuery );
        }

        //Session session = sessionFactory.openSession().getSession( EntityMode.DOM4J );
        Session session = sessionFactory.openSession();

        Query queryByParameters = session.getNamedQuery( namedQuery );

        if ( null != pids )
        {
            queryByParameters.setParameterList( "pids", pids );
        }

        if ( null != recordIdentifiers )
        {
            queryByParameters.setParameterList( "recordIdentifiers", recordIdentifiers );
        }

        if ( null != startDate )
        {
            queryByParameters.setParameter( "startDate", startDate );
        }

        if ( null != endDate )
        {
            queryByParameters.setParameter( "endDate", endDate );
        }

        List results = null;
        try
        {
            results = queryByParameters.list();
        }
        catch ( HibernateException e1 )
        {
            e1.printStackTrace();
        }

        for ( Object obj : results )
        {
            if ( obj instanceof DefaultElement )
            {
                DefaultElement e = ( DefaultElement )obj;

                if ( logger.isDebugEnabled() )
                {
                    logger.debug( namedQuery + '\n' + e.asXML() + '\n' );
                }
            }

        }
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vwPharmacyReadAndDetailReadNamedQueryTest( )
    {
        String opmpId = "81";

        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_5002" );

        List<String> recordIdentifiers = new ArrayList<String>();
        recordIdentifiers.add( "FILLER8_10054526.19/FILLER7_27990763.19/FILLER12_82224601.19/FILLER3_86286416.19" );

        executeNamedQuery( "OutpatientMedicationPromise.associations.sig", hdr2VWPharmacyDetailRead40010SessionFactory, null, null, null, null,
                        opmpId );

        executeNamedQuery( "OutpatientMedicationPromise.patient", hdr2VWPharmacyRead40010SessionFactory, pids, null, null, null, null );

        executeNamedQuery( "OutpatientMedicationPromise.patient", hdr2VWPharmacyDetailRead40010SessionFactory, pids, null, null, null, null );

        executeNamedQuery( "OutpatientMedicationPromise.patient.identifiers", hdr2VWPharmacyRead40010SessionFactory, pids, recordIdentifiers, null,
                        null, null );

        executeNamedQuery( "OutpatientMedicationPromise.patient.identifiers", hdr2VWPharmacyDetailRead40010SessionFactory, pids, recordIdentifiers,
                        null, null, null );
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vwIntoleranceConditionNamedQueryTest( )
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_10002" );

        List<String> recordIdentifiers = new ArrayList<String>();
        recordIdentifiers.add( "VISN14_64926037.4/605_120.8/VISN7_18680698.4/VISN10_65423063.4" );

        executeNamedQuery( "IntoleranceCondition.patient", hdr2VWIntoleranceConditionRead40010SessionFactory, pids, null, null, null, null );

        //        executeNamedQuery( "IntoleranceCondition.patient.date", hdr2VWIntoleranceConditionRead40010SessionFactory, pids, null, "3000101", "3100101",
        //                        null );

        executeNamedQuery( "IntoleranceCondition.patient.identifiers", hdr2VWIntoleranceConditionRead40010SessionFactory, pids, recordIdentifiers,
                        null, null, null );
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vwAllergiesReadNamedQueryTest( )
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_10002" );

        List<String> recordIdentifiers = new ArrayList<String>();
        recordIdentifiers.add( "VISN2_7671605.22/605_120.86/VISN4_48056319.22/VISN12_96989862.22" );

        executeNamedQuery( "AllergyAssessment.patient", hdr2VWAllergiesRead40010SessionFactory, pids, null, null, null, null );

        //executeNamedQuery( "AllergyAssessment.patient.date", hdr2VWAllergiesRead40010SessionFactory, pids, null, "3000101", "3100101", null );

        executeNamedQuery( "AllergyAssessment.patient.identifiers", hdr2VWAllergiesRead40010SessionFactory, pids, recordIdentifiers, null, null, null );
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vitalSignObservationEventPatientNamedQueryTest( )
        throws Exception
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_1" );

        String namedQuery = "VitalSignObservationEvent.patient";

        executeNamedQuery( namedQuery, hdr2VitalsignsRead40010SessionFactory, pids, null, null, null, null );


        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreate40020SessionFactory, pids, null, null, null, null );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create or Update Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreateOrUpdate40060SessionFactory, pids, null, null, null, null );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "VW Vitals Read Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VWVitalsignsRead40010SessionFactory, pids, null, null, null, null );
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vitalSignObservationEventPatientDateNamedQueryTest( )
        throws Exception
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_1" );

        String namedQuery = "VitalSignObservationEvent.patient.date";

        String startDate = "200001231235959.450-0600";
        String endDate = "202001231235959.450-0600";

        Element startDateElement = DocumentHelper.createElement( "literal1" );
        Element endDateElement = DocumentHelper.createElement( "literal2" );

        startDateElement.setText( startDate );
        endDateElement.setText( endDate );

        executeNamedQuery( namedQuery, hdr2VitalsignsRead40010SessionFactory, pids, null, ( Element )startDateElement.detach(),
                        ( Element )endDateElement.detach() );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreate40020SessionFactory, pids, null, "3000101", "3100101", null );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create or Update Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreateOrUpdate40060SessionFactory, pids, null, "3000101", "3100101", null );

        executeNamedQuery( namedQuery, hdr2VWVitalsignsRead40010SessionFactory, pids, null, "3000101", "3100101", null );
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void vitalSignObservationEventPatientIdentifiersNamedQueryTest( )
        throws Exception
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "605/test_sourceid_10" );

        List<String> recordIdentifiers = new ArrayList<String>();
        recordIdentifiers.add( "VISN6_36459749.61/605_120.5/VISN12_43168367.61/VISN4_45160000.61" );

        String namedQuery = "VitalSignObservationEvent.patient.identifiers";

        executeNamedQuery( namedQuery, hdr2VitalsignsRead40010SessionFactory, pids, recordIdentifiers, null, null, null );

      
        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Delete Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsDelete40030SessionFactory, null, recordIdentifiers, null, null, null );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreate40020SessionFactory, pids, recordIdentifiers, null, null, null );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( '\n' + "Vitals Create or Update Template Query" + '\n' );
        }

        executeNamedQuery( namedQuery, hdr2VitalsignsCreateOrUpdate40060SessionFactory, pids, recordIdentifiers, null, null, null );
    }


    //  @Test
    //  @Suite( groups = { "integrationtest" } )
    public void testTiuSinglePatientListDataFilter( )
        throws Exception
    {
        // create lists to be used by mocks
        List<PersonIdentifierInterface> resolvedPersonIdentifiers = new ArrayList<PersonIdentifierInterface>();
        List<EntryFilterInterface> entryFilters = new ArrayList<EntryFilterInterface>();
        Calendar startCalendar = new GregorianCalendar( 2000, 0, 1 );
        Calendar endCalendar = new GregorianCalendar( 2015, 11, 31 );
        Set<String> filterParameterNames = new HashSet<String>();
        QueryParameter<List<String>> documentTypeQueryParameter = new QueryParameter<List<String>>();
        List<String> documentTypes = new ArrayList<String>();

        // create required mocks.
        CdsFilterInterface cdsFilter = EasyMock.createMock( CdsFilterInterface.class );
        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        PersonIdentifierInterface pid1 = EasyMock.createMock( PersonIdentifierInterface.class );
        ParameterMapInterface parameterMap = EasyMock.createMock( ParameterMapInterface.class );

        // populate lists with mock objects
        resolvedPersonIdentifiers.add( pid1 );

        // populate entry filters list with single entry filter
        entryFilters.add( entryFilter );
        documentTypes.add( "4696095" );
        documentTypes.add( "4696107" );
        documentTypes.add( "4697146" );
        documentTypes.add( "4696112" );
        documentTypes.add( "4696113" );
        documentTypes.add( "4696119" );
        documentTypes.add( "4696120" );
        documentTypes.add( "4696125" );
        documentTypes.add( "4696444" );
        documentTypeQueryParameter.setName( "documentType" );
        documentTypeQueryParameter.setValue( documentTypes );

        // populate the filter parameter names set
        filterParameterNames.add( "documentType" );
        documentTypes.add( "" );

        // set expectations of mocks.
        EasyMock.expect( cdsFilter.getPersonIdentifiers() ).andReturn( resolvedPersonIdentifiers );
        EasyMock.expect( cdsFilter.getEntryPointFilters() ).andReturn( entryFilters );

        //     expectations for persistence locator (3 total read persistence managers)
        EasyMock.expect( entryFilter.getDomainEntryPoint() ).andReturn( "ClinicalDocumentEvent" );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "578" );
        EasyMock.expect( entryFilter.getDomainEntryPoint() ).andReturn( "ClinicalDocumentEvent" );
        EasyMock.expect( entryFilter.getDomainEntryPoint() ).andReturn( "ClinicalDocumentEvent" );

        //     expectations for site specific hibernate read persistence managers perform read on clinical data method.
        EasyMock.expect( entryFilter.getTemplateId() ).andReturn( "TiuDocumentListRead2" );
        EasyMock.expect( pid1.getAssigningFacility() ).andReturn( "578" );
        EasyMock.expect( pid1.getIdentity() ).andReturn( "775" );
        EasyMock.expect( entryFilter.getRecordIdentifiers() ).andReturn( null );
        EasyMock.expect( entryFilter.useDates() ).andReturn( Boolean.TRUE );
        EasyMock.expect( entryFilter.getStartDate() ).andReturn( startCalendar );
        EasyMock.expect( entryFilter.getEndDate() ).andReturn( endCalendar );
        EasyMock.expect( entryFilter.getAdditionalParametersMap() ).andReturn( parameterMap );
        EasyMock.expect( parameterMap.getFilterParameterNames() ).andReturn( filterParameterNames );
        //EasyMock.expect( parameterMap.getParameterValue( "documentType" ).andReturn( documentTypeQueryParameter );
        EasyMock.expect( documentTypeQueryParameter.getValue() ).andReturn( documentTypes );

        EasyMock.replay( cdsFilter, pid1, entryFilter );

        Assert.assertNotNull( transactionManager );
        List<Document> results = transactionManager.performReadOnClinicalData( "TiuDocumentListRead2", "testTiuSinglePatientListDataFilter1",
                        cdsFilter );
        for ( Document d : results )
        {
            System.out.println( d.asXML() );
        }
    }


    //  @Test
    //  @Suite( groups = { "integrationtest" } )
    public void testJdbcSelectOnRowId( )
        throws Exception
    {
        //Connection conn = this.vista521DataSource.getConnection();
        //      Statement stmt = conn.createStatement();
        //      ResultSet rs = stmt.executeQuery( "select rowid from vista.tiu_document_8925_ext" );
        //      while(rs.next())
        //      {
        //          System.out.println( rs.getLong( "rowid" ) );
        //      }
        //      
        //      stmt.close();
        //      conn.close();
    }


    @Test
    @Suite( groups = { "integrationtest" } )
    public void testHibernateQuerySelectOnRowId( )
        throws Exception
    {
        List<String> pids = new ArrayList<String>();
        pids.add( "237" );

        List<String> recordIdentifiers = new ArrayList<String>();
        recordIdentifiers.add( "82" );

        Session session = this.vista662TiuRead40012SessionFactory.openSession();
        Query byRecordIdentifier = session.getNamedQuery( "ClinicalDocumentEvent.patient.recordIdentifiers" );
        byRecordIdentifier.setParameterList( "pids", pids );
        byRecordIdentifier.setParameterList( "recordIdentifiers", recordIdentifiers );

        List results = byRecordIdentifier.list();

        for ( Object obj : results )
        {
            if ( obj instanceof DefaultElement )
            {
                DefaultElement e = ( DefaultElement )obj;
                System.out.println( e.asXML() );
            }

        }
    }
}
