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

import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;

import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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.persistence.PersistenceException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class LegacyFilterParameterExtractorTest
{

    @Before
    public void setUp( )
        throws Exception
    {
    }


    @After
    public void tearDown( )
        throws Exception
    {
    }


    @SuppressWarnings( "unchecked" )
    @Test
    public void testExtractNamedParametersRecordIdentifiers( )
    {
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        List<String> recordIdentifiers = createMock(List.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(true);
        expect( entryFilter.getRecordIdentifiers()).andReturn(recordIdentifiers);
        expect( parameterTransformerMap.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS )).andReturn( null );
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( null );
        expect( entryFilter.containsXpathFilterExpression() ).andReturn( false );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, recordIdentifiers );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

        // verify the results
        assertTrue(parameters.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS ) == recordIdentifiers );
        verify( entryFilter, parameterTransformerMap, recordIdentifiers );
    }
    
    @SuppressWarnings( "unchecked" )
    @Test
    public void testExtractNamedParametersRecordIdentifiersContainsXpathFilter( )
    {
        String xpathFilterExpression = "//xpathFilterExpression";
        
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        List<String> recordIdentifiers = createMock(List.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(true);
        expect( entryFilter.getRecordIdentifiers()).andReturn(recordIdentifiers);
        expect( parameterTransformerMap.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS )).andReturn( null );
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( null );
        expect( entryFilter.containsXpathFilterExpression() ).andReturn( true );
        expect( entryFilter.getXpathFilterExpression()).andReturn( xpathFilterExpression );
        expect( entryFilter.getXpathFilterExpressionNamespace()).andReturn( "http://hdr.med.DNS   /test" );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, recordIdentifiers );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

        // verify the results
        assertTrue(parameters.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS ) == recordIdentifiers );
        assertTrue(parameters.get( FilterParameterExtractorInterface.PN_XPATH_FILTER_EXPRESSION ).equals(xpathFilterExpression) );
        verify( entryFilter, parameterTransformerMap, recordIdentifiers );
    }
    
    @SuppressWarnings( "unchecked" )
    @Test
    public void testExtractNamedParametersRecordIdentifiersCustomTransformer( )
    {
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        QueryParameterTransformerInterface customRecordIdParamTransformer = createMock(QueryParameterTransformerInterface.class);
        List<String> recordIdentifiers = createMock(List.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(true);
        expect( parameterTransformerMap.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS )).andReturn( customRecordIdParamTransformer );
        expect( entryFilter.getRecordIdentifiers()).andReturn(recordIdentifiers);
        customRecordIdParamTransformer.transformAndSetParameter( eq(FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS), eq(recordIdentifiers), anyObject(Map.class));
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( null );
        expect( entryFilter.containsXpathFilterExpression() ).andReturn( false );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, customRecordIdParamTransformer, recordIdentifiers );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

        // verify the results
        //assertTrue(parameters.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS ) == recordIdentifiers );
        verify( entryFilter, parameterTransformerMap, customRecordIdParamTransformer, recordIdentifiers );
    }
    
    @SuppressWarnings( "unchecked" )
    @Test
    public void testExtractNamedParametersUsesDates( )
    {
        Calendar startDate = Calendar.getInstance();
        Calendar endDate = Calendar.getInstance();
        
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        QueryParameterTransformerInterface startDateTransformer = createMock(QueryParameterTransformerInterface.class);
        QueryParameterTransformerInterface endDateTransformer = createMock(QueryParameterTransformerInterface.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(false);
        expect( entryFilter.useDates() ).andReturn(true);
        expect( parameterTransformerMap.get(FilterParameterExtractorInterface.PN_START_DATE)).andReturn( startDateTransformer );
        expect( entryFilter.getStartDate()).andReturn( startDate );
        startDateTransformer.transformAndSetParameter( eq(FilterParameterExtractorInterface.PN_START_DATE), eq(startDate), anyObject(Map.class) );
        expect( parameterTransformerMap.get(FilterParameterExtractorInterface.PN_END_DATE)).andReturn( endDateTransformer );
        expect( entryFilter.getEndDate() ).andReturn( endDate );
        endDateTransformer.transformAndSetParameter( eq(FilterParameterExtractorInterface.PN_END_DATE), eq(endDate), anyObject(Map.class) );
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( null );
        expect( entryFilter.containsXpathFilterExpression() ).andReturn( false );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, startDateTransformer, endDateTransformer );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

        // verify the results
        verify( entryFilter, parameterTransformerMap, startDateTransformer, endDateTransformer );
    }
    
    
    @SuppressWarnings( "unchecked" )
    @Test( expected=PersistenceException.class )
    public void testExtractNamedParametersUsesDatesNoStartDateTranformerError( )
    {
        Calendar startDate = Calendar.getInstance();
        Calendar endDate = Calendar.getInstance();
        
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        QueryParameterTransformerInterface startDateTransformer = createMock(QueryParameterTransformerInterface.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(false);
        expect( entryFilter.useDates() ).andReturn(true);
        expect( parameterTransformerMap.get(FilterParameterExtractorInterface.PN_START_DATE)).andReturn( null );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, startDateTransformer );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

    }
    
    @SuppressWarnings( "unchecked" )
    @Test (expected=PersistenceException.class)
    public void testExtractNamedParametersUsesDatesNoEndDateTransformerError( )
    {
        Calendar startDate = Calendar.getInstance();
        
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        QueryParameterTransformerInterface startDateTransformer = createMock(QueryParameterTransformerInterface.class);
        QueryParameterTransformerInterface endDateTransformer = createMock(QueryParameterTransformerInterface.class);
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(false);
        expect( entryFilter.useDates() ).andReturn(true);
        expect( parameterTransformerMap.get(FilterParameterExtractorInterface.PN_START_DATE)).andReturn( startDateTransformer );
        expect( entryFilter.getStartDate()).andReturn( startDate );
        startDateTransformer.transformAndSetParameter( eq(FilterParameterExtractorInterface.PN_START_DATE), eq(startDate), anyObject(Map.class) );
        expect( parameterTransformerMap.get(FilterParameterExtractorInterface.PN_END_DATE)).andReturn( null );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, startDateTransformer, endDateTransformer );
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

    }
    
    @SuppressWarnings( { "unchecked", "rawtypes" } )
    @Test
    public void testExtractNamedParametersAdditionalParameters( )
    {
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        List<String> recordIdentifiers = createMock(List.class);
        ParameterMapInterface additionalParams = createMock( ParameterMapInterface.class );
        Set<String> filterNames = createMock( Set.class );
        Iterator<String> filterNamesIterator = createMock( Iterator.class );
        QueryParameter facilityIdQueryParameter = createMock( QueryParameter.class );
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(true);
        expect( entryFilter.getRecordIdentifiers()).andReturn(recordIdentifiers);
        expect( parameterTransformerMap.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS )).andReturn( null );
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( additionalParams );
        expect( additionalParams.getFilterParameterNames()).andReturn( filterNames );
        expect( filterNames.iterator()).andReturn( filterNamesIterator );
        expect( filterNamesIterator.hasNext()).andReturn( true );
        expect( filterNamesIterator.next()).andReturn( "facilityId" );
        expect( additionalParams.getParameterValue( "facilityId" )).andReturn( facilityIdQueryParameter );
        expect( facilityIdQueryParameter.getValue() ).andReturn( "200" );
        expect( filterNamesIterator.hasNext() ).andReturn( false );
        expect( entryFilter.containsXpathFilterExpression() ).andReturn( false );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, recordIdentifiers, additionalParams, filterNames, filterNamesIterator );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );

        // verify the results
        assertTrue(parameters.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS ) == recordIdentifiers );
        verify( entryFilter, parameterTransformerMap, recordIdentifiers, additionalParams, filterNames, filterNamesIterator );
    }
    
    @SuppressWarnings( { "unchecked", "rawtypes" } )
    @Test ( expected=PersistenceException.class )
    public void testExtractNamedParametersAdditionalParametersUnexpectedError( )
    {
        // mock objects to use in test
        EntryFilterInterface entryFilter = createMock( EntryFilterInterface.class );
        Map<String, QueryParameterTransformerInterface> parameterTransformerMap = createMock(Map.class);
        List<String> recordIdentifiers = createMock(List.class);
        ParameterMapInterface additionalParams = createMock( ParameterMapInterface.class );
        Set<String> filterNames = createMock( Set.class );
        Iterator<String> filterNamesIterator = createMock( Iterator.class );
        
        // set expectations for mock objects
        expect( entryFilter.hasRecordIdentifiers() ).andReturn(true);
        expect( entryFilter.getRecordIdentifiers()).andReturn(recordIdentifiers);
        expect( parameterTransformerMap.get( FilterParameterExtractorInterface.PN_RECORD_IDENTIFIERS )).andReturn( null );
        expect( entryFilter.getAdditionalParametersMap() ).andReturn( additionalParams );
        expect( additionalParams.getFilterParameterNames()).andReturn( filterNames );
        expect( filterNames.iterator()).andReturn( filterNamesIterator );
        expect( filterNamesIterator.hasNext()).andReturn( true );
        expect( filterNamesIterator.next()).andReturn( "facilityId" );
        expect( additionalParams.getParameterValue( "facilityId" )).andReturn( null );
        
        // get the mocks read for use
        replay( entryFilter, parameterTransformerMap, recordIdentifiers, additionalParams, filterNames, filterNamesIterator );
        
        
        FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
        Map<String, Object> parameters = filterParameterExtractor.extractNamedParameters( parameterTransformerMap, entryFilter );
  
    }

}
