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

import static org.powermock.api.easymock.PowerMock.*;

import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;

import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.junit.runners.PowerMockSuiteAwareRunner;
import gov.va.med.cds.persistence.QueryAssociationInterface;
import gov.va.med.cds.persistence.QueryWorkInterface;
import gov.va.med.cds.persistence.hibernate.common.PointInTimeUserType;
import gov.va.med.cds.persistence.hibernate.interceptor.XmlTypeExtractQueryInterceptor;

import java.util.List;
import java.util.Map;

import org.dom4j.DocumentHelper;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.internal.SessionImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;

@RunWith( PowerMockSuiteAwareRunner.class )
@PrepareForTest(SessionImpl.class)
public class XmlTypeQueryWorkTest
{
    
    private static final String XPATH_EXPRESSION = "//an/xpath/extract/[@expression='true']";
    private static final String XPATH_EXPRESSION_NAMESPACE = "http://hdr.med.DNS   ";

    @Before
    public void setUp( )
        throws Exception
    {
    }


    @After
    public void tearDown( )
        throws Exception
    {
    }


    @Test
    public void testBuildQuery( )
    {
        // set up the mock objects for the test
        SessionImpl session = PowerMock.createMock( SessionImpl.class );
        QueryAssociationInterface queryAssociation = createMock( QueryAssociationInterface.class );
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        QueryNameBuilderInterface queryNameBuilder = createMock( QueryNameBuilderInterface.class );
        FilterParameterExtractorInterface filterParameterExtractor = createMock( FilterParameterExtractorInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock( Map.class );
        Map<String, Object> filterParameters = createMock( Map.class );
        QueryParameterBinderInterface queryParameterBinder = createMock( QueryParameterBinderInterface.class );
        Map<String, String> templateTimeoutMap = createMock( Map.class );
        List<String> personIdentifiers = createMock( List.class );
        QueryParameterTransformerInterface pidsParameterTransformer = createMock( QueryParameterTransformerInterface.class );
        XmlTypeExtractQueryInterceptor interceptor = createMock( XmlTypeExtractQueryInterceptor.class );
        Query query = createMock( Query.class );
        ScrollableResults scrollableResults = createMock( ScrollableResults.class );
        
        // set the expectations for the request
        expect(queryAssociation.getAssociationName()).andReturn( "association" );
        expect(queryNameBuilder.buildQueryName( entryFilter, "association" )).andReturn( "templateId.clinicalDomainName.association.date" );
        expect(session.getNamedQuery( "templateId.clinicalDomainName.association.date" )).andReturn( query );
        expect(filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter )).andReturn( filterParameters );
        expect(entryFilter.isPatientCentricFilter()).andReturn( true );
        expect(parameterTransformerMap.get( FilterParameterExtractorInterface.PN_PERSON_IDENTIFIERS )).andReturn( pidsParameterTransformer );
        pidsParameterTransformer.transformAndSetParameter( eq(FilterParameterExtractorInterface.PN_PERSON_IDENTIFIERS), eq(personIdentifiers), anyObject(Map.class) );
        expect(queryParameterBinder.bindQueryParameters( query, filterParameters, PointInTimeUserType.class )).andReturn(query);
        expect(entryFilter.getXpathExtractExpression()).andReturn(XPATH_EXPRESSION).anyTimes();
        expect(session.getInterceptor()).andReturn( interceptor );
        interceptor.setExtractExpression( XPATH_EXPRESSION );
        interceptor.setExtractExpressionNamespace( XPATH_EXPRESSION_NAMESPACE );
        expect(query.setReadOnly( true )).andReturn( query );
        expect(query.scroll()).andReturn(scrollableResults);
        expect(scrollableResults.last()).andReturn( true );
        expect(scrollableResults.getRowNumber()).andReturn( 100 );
        expect(entryFilter.isCountOnly()).andReturn(false);
        expect(entryFilter.isPagingFilter()).andReturn( true ).anyTimes();
        expect(queryAssociation.getFilterModelName()).andReturn( "entryPoint" ).anyTimes();
        expect(entryFilter.getDomainEntryPoint()).andReturn( "entryPoint").anyTimes();
        expect(entryFilter.getPageNumber()).andReturn( 1 );
        expect(entryFilter.getPageSize()).andReturn( 20 ).anyTimes();
        expect(query.setFirstResult( 0 )).andReturn( query );
        expect(query.setMaxResults( 20 )).andReturn( query );
        expect(query.scroll()).andReturn( scrollableResults );
        expect(scrollableResults.first()).andReturn( true );
        expect(scrollableResults.get()).andReturn( new Object[] { DocumentHelper.createElement( "clinicalDocument" ) } );
        expect(scrollableResults.next()).andReturn( false );
        expect(scrollableResults.last()).andReturn( true );
        expect(scrollableResults.getRowNumber()).andReturn( 0 );
        expect(scrollableResults.getRowNumber()).andReturn( 0 );
        
        
        // get the mocks ready to be used in the test
        replay( session, queryAssociation, entryFilter, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
                        queryParameterBinder, personIdentifiers, query, scrollableResults, filterParameters,
                        pidsParameterTransformer, interceptor);
        
        QueryWorkInterface queryWork = new XmlTypeQueryWork( session, queryAssociation, entryFilter, queryNameBuilder, 
                        filterParameterExtractor, parameterTransformerMap, queryParameterBinder, 
                        personIdentifiers, PointInTimeUserType.class, "applicationName", "siteId" );
        
        queryWork.run();
        
        
        // verify the results of the test
        verify( session, queryAssociation, entryFilter, queryNameBuilder, filterParameterExtractor, parameterTransformerMap, 
                        queryParameterBinder, personIdentifiers, query, scrollableResults, filterParameters,
                        pidsParameterTransformer, interceptor );
    }

}