

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


import static org.easymock.EasyMock.expect;
import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.persistence.QueryAssociationInterface;
import gov.va.med.cds.persistence.hibernate.common.VistaPointInTimeUserType;
import gov.va.med.cds.template.TemplateHelperInterface;
import gov.va.med.cds.template.generated.JaxBMarshallerUnmarshaller;
import gov.va.med.cds.template.generated.allergies.IntoleranceCondition;
import gov.va.med.cds.util.TimeoutUtil;

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

import org.easymock.EasyMock;
import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;


@SuppressWarnings( { "rawtypes", "unchecked" } )
public class DefaultQueryWorkTest
{
    @Autowired
    protected TemplateHelperInterface templateHelper;

    private String applicationName = "CDS";


    @Test
    @Suite( groups = { "checkintest" } )
    public void testBuildQueryWithRecordIdentfiers( )
        throws Exception
    {
        String templateId = "TestTemplateId";
        String requestId = "TestRequestId";
        String domainEntryPoint = "ClinicalDocumentEvent";
        String siteId = "999";
        Set<String> paramNames = new HashSet<String>();
        paramNames.add( "documentClass" );
        List<String> recordIdentifiers = new ArrayList<String>();
        String recordIdentifier = "010101010101010110UUID";
        recordIdentifiers.add( recordIdentifier );
        String queryName = "TestTemplateId.ClinicalDocumentEvent.documentClass.identifiers.person.documentClass";
        String associationName = "documentClass";
        Map<String, Object> queryParametersMap = new HashMap<String, Object>();
        List<Object> resultList = new ArrayList<Object>();
        resultList.add( new IntoleranceCondition() );
        List<String> personIdentifiers = new ArrayList<String>();
        personIdentifiers.add( "552/PersonIdentifier-10009" );
        Map<String, String> templateTimeoutMap = new HashMap<String, String>();
        templateTimeoutMap.put( TimeoutUtil.UPPER_LIMIT_TIMEOUT, "300" );

        //Mocks      
        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
        Query query = EasyMock.createMock( Query.class );
        Session session = EasyMock.createMock( Session.class );
        QueryAssociationInterface queryAssociation = EasyMock.createMock( QueryAssociationInterface.class );
        Connection connection = EasyMock.createMock( Connection.class );
        QueryNameBuilderInterface queryNameBuilder = EasyMock.createMock( QueryNameBuilderInterface.class );
        FilterParameterExtractorInterface filterParameterExtractor = EasyMock.createMock( FilterParameterExtractorInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = EasyMock.createMock(Map.class);
        QueryParameterBinderInterface queryParameterBinder = EasyMock.createMock(QueryParameterBinderInterface.class);

        //setup the expects
        expect( queryAssociation.getAssociationName() ).andReturn( associationName ).anyTimes();
        expect( filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter )).andReturn(queryParametersMap);
        expect( entryFilter.isPatientCentricFilter()).andReturn( true );
        expect( parameterTransformerMap.get( "pids" )).andReturn( null );
        expect( queryNameBuilder.buildQueryName( entryFilter, associationName )).andReturn( queryName );
        expect( session.getNamedQuery(queryName)).andReturn(query);
        expect( queryParameterBinder.bindQueryParameters( query, queryParametersMap, VistaPointInTimeUserType.class )).andReturn(query);
        expect( entryFilter.getTimeout()).andReturn( null );
        expect( entryFilter.getRequestId()).andReturn( requestId ).anyTimes();
        expect( entryFilter.getTemplateId()).andReturn( templateId ).anyTimes();
        expect( entryFilter.getDomainEntryPoint()).andReturn( domainEntryPoint ).anyTimes();
        //expect( session.getEntityMode()).andReturn( EntityMode.DOM4J ).anyTimes();
        expect( query.setTimeout( 300 )).andReturn(query);
        expect( query.list()).andReturn(resultList);
        expect( session.isOpen() ).andReturn( true );
        expect( session.close() ).andReturn( connection );
        
        EasyMock.replay( entryFilter, query, session, queryAssociation, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
                        queryParameterBinder );
        
        DefaultQueryWork work = new DefaultQueryWork( session, queryAssociation, entryFilter, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
                        queryParameterBinder, templateTimeoutMap, personIdentifiers, VistaPointInTimeUserType.class, queryName, siteId, new JaxBMarshallerUnmarshaller() );

        work.run();

        Assert.assertNotNull( work.getResults() );
        Assert.assertNotNull( work.getResults().element( "intoleranceConditions" ) );
        Assert.assertTrue( work.getExceptions().size() == 0 );

        //just for coverage
        Assert.assertFalse( work.isDaemon() );
        work.release();

        EasyMock.verify( entryFilter, query, session, queryAssociation, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
                        queryParameterBinder );
    }


//    @Test
//    @Suite( groups = { "checkintest" } )
//    public void testBuildQueryWithDates( )
//    {
//
//        String templateId = "TestTemplateId";
//        String requestId = "Request-9999";
//        String domainEntryPoint = "ClinicalDocumentEvent";
//        String siteId = "TestSiteId";
//        Set<String> paramNames = new HashSet<String>();
//        paramNames.add( "documentClass" );
//        String queryName = "TestTemplateId.ClinicalDocumentEvent.documentClass.date.documentClass";
//
//        GregorianCalendar startDate = new GregorianCalendar();
//        GregorianCalendar endDate = new GregorianCalendar();
//        Date startD = new Date( System.currentTimeMillis() );
//        Date endD = new Date( System.currentTimeMillis() + 1000 );
//        startDate.setTime( startD );
//        endDate.setTime( endD );
//
//        //mocks
//        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
//        QueryAssociationInterface queryAssociation = EasyMock.createMock( QueryAssociationInterface.class );
//        FilterParameterExtractorInterface filterParameterExtractor = EasyMock.createMock( FilterParameterExtractorInterface.class );
//        QueryNameBuilderInterface queryNameBuilder = EasyMock.createMock( QueryNameBuilderInterface.class );
//        Session session = EasyMock.createMock( Session.class );
//        Query query = EasyMock.createMock( Query.class );
//        QueryParameterBinderInterface queryParameterBinder = EasyMock.createMock(QueryParameterBinderInterface.class);
//        
//
//        //setup the Expects
//        expect( queryAssociation.getAssociationName() ).andReturn( "association" );
//        
//        
//        expect( entryFilter.hasRecordIdentifiers()).andReturn( Boolean.FALSE ).anyTimes();
//        expect( entryFilter.useDates() ).andReturn( Boolean.TRUE ).anyTimes();
//        expect( entryFilter.containsXpathFilterExpression() ).andReturn( Boolean.FALSE ).anyTimes();
//        expect( entryFilter.getAdditionalParametersMap() ).andReturn( optionalParameterMap ).anyTimes();
//        expect( entryFilter.isPatientCentricFilter()).andReturn( Boolean.TRUE );
//        expect( entryFilter.getTemplateId() ).andReturn( templateId ).anyTimes();
//        expect( entryFilter.getRequestId() ).andReturn( requestId ).anyTimes();
//        expect( entryFilter.getDomainEntryPoint() ).andReturn( domainEntryPoint ).anyTimes();
//        expect( entryFilter.getTimeout() ).andReturn( null ).anyTimes();
//        expect( entryFilter.getStartDate() ).andReturn( startDate );
//        expect( entryFilter.getEndDate() ).andReturn( endDate );
//
//        expect( optionalParameterMap.getFilterParameterNames() ).andReturn( paramNames ).anyTimes();
//
//        //could not figure out how to Mock this Parameter Type object - using a real instance - it is a minor object - no logic
//        QueryParameter optionalParameter = new QueryParameter<String>();
//        optionalParameter.setName( "documentClass" );
//        optionalParameter.setValue( "PROGRESS NOTES" );
//        expect( optionalParameterMap.getParameterValue( "documentClass" ) ).andReturn( optionalParameter );
//
//        expect( query.setParameter( "documentClass", "PROGRESS NOTES" ) ).andReturn( query );
//
//        expect( session.getNamedQuery( queryName ) ).andReturn( query );
//
//        expect( query.setParameter( EasyMock.eq( "startDate" ), EasyMock.isA( PointInTime.class ), EasyMock.isA( Type.class ) ) ).andReturn( query );
//        expect( query.setParameter( EasyMock.eq( "endDate" ), EasyMock.isA( PointInTime.class ), EasyMock.isA( Type.class ) ) ).andReturn( query );
//
//        List<String> personIdentifiers = new ArrayList<String>();
//        personIdentifiers.add( "552/PersonIdentifier-10009" );
//        expect( query.setParameterList( "pids", personIdentifiers ) ).andReturn( query );
//
//        expect( query.setTimeout( 300 ) ).andReturn( query ).anyTimes();
//
//        //using Element instead of a Mock (it is a very simple element) so that coverage call below to getResults() can obtain a real data object
//        List<Element> resultList = new ArrayList<Element>();
//        resultList.add( DocumentHelper.createElement( "clinicalDocument" ) );
//        expect( query.list() ).andReturn( resultList );
//
//        expect( session.isOpen() ).andReturn( true );
//        expect( session.close() ).andReturn( connection );
//        expect( queryAssociation.getAssociationName() ).andReturn( "documentClass" ).anyTimes();
//
//        EasyMock.replay( entryFilter, optionalParameterMap, query, session, queryAssociation, personIdentifier );
//
//        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = new HashMap<String, QueryParameterTransformerInterface>();
//        parameterTransformerMap.put( "startDate", new PointInTimeQueryParameterTransformer() );
//        parameterTransformerMap.put( "endDate", new PointInTimeQueryParameterTransformer() );
//        
//        DefaultQueryParameterBinder queryParamBinder = new DefaultQueryParameterBinder();
//        
//        DefaultQueryWork work = new DefaultQueryWork( session, queryAssociation, entryFilter, new LegacyQueryNameBuilder(), new LegacyFilterParameterExtractor(), parameterTransformerMap, 
//                        queryParamBinder, personIdentifiers, Dom4jPointInTimeUserType.class, applicationName, siteId );
//                        
//
//        Map<String, String> templateTimeoutMap = new HashMap<String, String>();
//        templateTimeoutMap.put( TimeoutUtil.UPPER_LIMIT_TIMEOUT, "300" );
//        work.setTemplateTimeoutMap( templateTimeoutMap );
//
//        work.run();
//
//        Assert.assertNotNull( work.getResults() );
//        Assert.assertNotNull( work.getResults().element( "clinicalDocument" ) );
//        Assert.assertTrue( work.getExceptions().size() == 0 );
//
//        //just for coverage
//        Assert.assertFalse( work.isDaemon() );
//        work.release();
//        Assert.assertEquals( work.getQueryAssociation(), queryAssociation );
//
//        EasyMock.verify( entryFilter, optionalParameterMap, query, session, queryAssociation, personIdentifier );
//    }


//    @Test
//    @Suite( groups = { "checkintest" } )
//    public void testBuildQueryException( )
//    {
//        String templateId = "IntoleranceConditionRead40010";
//        String requestId = "Request-9999";
//        String domainEntryPoint = "ClinicalDocumentEvent";
//        String siteId = "TestSiteId";
//        Set<String> paramNames = new HashSet<String>();
//        paramNames.add( "documentClass" );
//
//        GregorianCalendar startDate = new GregorianCalendar();
//        GregorianCalendar endDate = new GregorianCalendar();
//        Date startD = new Date( System.currentTimeMillis() );
//        Date endD = new Date( System.currentTimeMillis() + 1000 );
//        startDate.setTime( startD );
//        endDate.setTime( endD );
//
//        //mocks
//        EntryFilterInterface entryFilter = EasyMock.createMock( EntryFilterInterface.class );
//        QueryAssociationInterface queryAssociation = EasyMock.createMock( QueryAssociationInterface.class );
//        FilterParameterExtractorInterface filterParameterExtractor = createMock( FilterParameterExtractorInterface.class );
//        QueryNameBuilderInterface queryNameBuilder = createMock(QueryNameBuilderInterface.class);
//        Query query = EasyMock.createMock( Query.class );
//        Session session = EasyMock.createMock( Session.class );
//        
//
//        /*
//         * ExceptionHandler is static - and so its internal objects cannot be MOCKs
//         * can cause other integrated tests to use an un expecting Mock proxy which can cause build issues.
//        */
////        ClinicalDataResponseInterface clinicalDataResponse = new ClinicalDataResponse400();
////        ExceptionLoggerInterface guaranteedLogger = new DefaultLogger();
////        ExceptionHandler.setGuaranteedLogger( guaranteedLogger );
////        ExceptionHandler.setTemplateHelper( templateHelper );
////        ExceptionHandler.setClinicalDataResponse( clinicalDataResponse );
//
//        //setup the Expects
//        expect( queryAssociation.getAssociationName() ).andReturn( "association" );
//        expect( filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter )).andReturn( queryParametersMap );
//        
//        expect( entryFilter.hasRecordIdentifiers()).andReturn( Boolean.FALSE ).anyTimes();
//        expect( entryFilter.useDates() ).andReturn( Boolean.TRUE ).anyTimes();
//        expect( entryFilter.getStartDate() ).andReturn( startDate );
//        expect( entryFilter.getEndDate() ).andReturn( endDate );
//        expect( entryFilter.containsXpathFilterExpression() ).andReturn( Boolean.FALSE ).anyTimes();
//        expect( entryFilter.getAdditionalParametersMap() ).andReturn( optionalParameterMap ).anyTimes();
//        expect( optionalParameterMap.getParameterValue( "documentClass" )).andReturn( new QueryParameter() );
//        expect( entryFilter.getTemplateId() ).andReturn( templateId ).anyTimes();
//        expect( entryFilter.getRequestId() ).andReturn( requestId ).anyTimes();
//        expect( entryFilter.getDomainEntryPoint() ).andReturn( domainEntryPoint ).anyTimes();
//        expect( entryFilter.getTimeout() ).andReturn( null ).anyTimes();
//        
//        expect( optionalParameterMap.getFilterParameterNames() ).andReturn( paramNames );
//        
//        expect( session.getNamedQuery( EasyMock.anyObject(String.class) )).andThrow( new RuntimeException( "No named query." ) );
//        
//        List<String> personIdentifiers = new ArrayList<String>();
//        personIdentifiers.add( "552/PersonIdentifier-10009" );
//
//        expect( session.isOpen() ).andReturn( true );
//        expect( session.close() ).andReturn( connection );
//        expect( queryAssociation.getAssociationName() ).andReturn( "documentClass" ).anyTimes();
//
//        EasyMock.replay( entryFilter, optionalParameterMap, query, session, queryAssociation, personIdentifier );
//
//        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = new HashMap<String, QueryParameterTransformerInterface>();
//        parameterTransformerMap.put( "startDate", new PointInTimeQueryParameterTransformer() );
//        parameterTransformerMap.put( "endDate", new PointInTimeQueryParameterTransformer() );
//        
//        DefaultQueryParameterBinder queryParamBinder = new DefaultQueryParameterBinder();
//        
//        DefaultQueryWork work = new DefaultQueryWork( session, queryAssociation, entryFilter, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
//                        queryParamBinder, personIdentifiers, Dom4jPointInTimeUserType.class, applicationName, siteId );
//
//        Map<String, String> templateTimeoutMap = new HashMap<String, String>();
//        templateTimeoutMap.put( TimeoutUtil.UPPER_LIMIT_TIMEOUT, "300" );
//        work.setTemplateTimeoutMap( templateTimeoutMap );
//
//        work.run();
//
//        Assert.assertNotNull( work.getResults() );
//        Assert.assertNull( work.getResults().element( "clinicalDocument" ) );
//        Assert.assertTrue( work.getExceptions().size() > 0 );
//
//        //just for coverage
//        Assert.assertFalse( work.isDaemon() );
//        work.release();
//        Assert.assertEquals( work.getQueryAssociation(), queryAssociation );
//
//        EasyMock.verify( entryFilter, optionalParameterMap, query, session, queryAssociation, personIdentifier );
//    }
}
