

package gov.va.med.cds.filter.vhim400;


import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.common.person.correlation.PersonIdentifierCorrelationServiceInterface;
import gov.va.med.cds.common.person.correlation.PersonIdentifierInterface;
import gov.va.med.cds.filter.FilterPatientResolverException;
import gov.va.med.cds.filter.PersonIdentifierBuilder;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.util.StreamUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import javax.annotation.Resource;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.FileSystemResource;


@RunWith( SuiteAwareRunner.class )
public class SinglePatientResolverTest
{
    private String filterId = "AA_SINGLE_PATIENT_ALL_DATA_FILTER";
    private SinglePatientResolver filterPatientResolver = new SinglePatientResolver();


    @Before
    @Suite( groups = { "checkintest" } )
    public void beforeEachTest( )
    {
        Collection<PersonIdentifierInterface> identityCollection = new ArrayList<PersonIdentifierInterface>();
        identityCollection.add( PersonIdentifierBuilder.build( "MED.VA.GOV", "555", "local_id_1" ) );
        identityCollection.add( PersonIdentifierBuilder.build( "MED.VA.GOV", "556", "local_id_2" ) );

        PersonIdentifierInterface nationalId = PersonIdentifierBuilder.build( "USVHA", "200M", "1008523096V381537" );
        PersonIdentifierInterface invalidNationalId = PersonIdentifierBuilder.build( "USVHA", "200M", "1009523096V381537" );

        PersonIdentifierCorrelationServiceInterface mockIdmService = createNiceMock( PersonIdentifierCorrelationServiceInterface.class );
        filterPatientResolver.setPatientIdentifierCorrelationService( mockIdmService );
        expect( mockIdmService.obtainPersonIdentifiers( nationalId ) ).andReturn( identityCollection ).anyTimes();

        expect( mockIdmService.obtainPersonIdentifiers( invalidNationalId ) ).andReturn( null ).anyTimes();

        replay( mockIdmService );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNationalIdOnly( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNationalId.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        String filterWithResolvedIds = filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument ).asXML();
        assertTrue( filterWithResolvedIds.contains( "patients" ) );
        assertTrue( filterWithResolvedIds.contains( "resolvedIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "NationalId" ) );
        assertTrue( checkResolvedIdentifiers( filterWithResolvedIds, 2 ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_1" ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_2" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithResolvedIds( )
        throws IOException, DocumentException
    {
        String filterWithResolvedIds = StreamUtil.resourceToString( new FileSystemResource(
        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithResolvedIds.xml" ) );

        Document filterRequestDocument = DocumentHelper.parseText( filterWithResolvedIds );
        
        String filterPostResolution = filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument ).asXML();
        assertTrue( filterPostResolution.contains( "patients" ) );
        assertTrue( filterPostResolution.contains( "resolvedIdentifiers" ) );
        assertFalse( filterPostResolution.contains( "NationalId" ) );
        assertTrue( checkResolvedIdentifiers( filterPostResolution, 2 ) );
        assertTrue( filterPostResolution.contains( "local_id_1" ) );
        assertTrue( filterPostResolution.contains( "local_id_2" ) );
    }

    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithEdipi( )
        throws IOException, DocumentException
    {
 
        String filterWithEdipi = StreamUtil.resourceToString( new FileSystemResource(
        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithEdipi.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithEdipi );

        String filterPostResolution = filterPatientResolver.resolveIdentifiersInFilter( "HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER", filterRequestDocument ).asXML();

        assertTrue( filterPostResolution.contains( "patients" ) );
        assertTrue( filterPostResolution.contains( "EdiPi" ) );
        assertFalse( filterPostResolution.contains( "resolvedIdentifiers" ) );
        assertFalse( filterPostResolution.contains( "NationalId" ) );
        assertFalse( checkResolvedIdentifiers( filterPostResolution, 2 ) );
        assertTrue( filterPostResolution.contains( "local_id_1" ) );
        
    }

    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNationalIdAndExcludeId( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNIdAndExcludeId.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        
        String filterWithResolvedIds = filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument ).asXML();
        assertTrue( filterWithResolvedIds.contains( "patients" ) );
        assertTrue( filterWithResolvedIds.contains( "resolvedIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "NationalId" ) );
        assertTrue( filterWithResolvedIds.contains( "excludeIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_1" ) );
        assertTrue( checkResolvedIdentifiers( filterWithResolvedIds, 1 ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_2" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNationalIdAndExcludeFaclility( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNIdAndExcludeFacility.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        
        String filterWithResolvedIds = filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument ).asXML();
        assertTrue( filterWithResolvedIds.contains( "patients" ) );
        assertTrue( filterWithResolvedIds.contains( "resolvedIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "NationalId" ) );
        assertTrue( filterWithResolvedIds.contains( "excludeIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_2" ) );
        assertTrue( checkResolvedIdentifiers( filterWithResolvedIds, 1 ) );
        assertFalse( filterWithResolvedIds.contains( "local_id_1" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithExcludeAuthority( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNIdAndExcludeAuthority.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        
        String filterWithResolvedIds = filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument ).asXML();
        assertTrue( filterWithResolvedIds.contains( "patients" ) );
        assertTrue( filterWithResolvedIds.contains( "resolvedIdentifiers" ) );
        assertTrue( filterWithResolvedIds.contains( "NationalId" ) );
        assertTrue( checkResolvedIdentifiers( filterWithResolvedIds, 2 ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_1" ) );
        assertTrue( filterWithResolvedIds.contains( "local_id_2" ) );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithAllExcluded( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNIdAndAllExcluded.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        
        filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithInvalidNid( )
        throws IOException, DocumentException
    {
        String filterWithNationalId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithInvalidNId.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationalId );
        
        filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithMultipleNids( )
        throws IOException, DocumentException
    {
        String filterWithNIds = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithMultipleNIds.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNIds );
        
        filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNoIds( )
        throws IOException, DocumentException
    {
        String filterWithNoIds = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNoIds.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNoIds );
        
        filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNoPatients( )
        throws IOException, DocumentException
    {
        String filterWithNoPatients = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNoPatients.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNoPatients );
        
        filterPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithNullFilter( )
        throws IOException
    {
        filterPatientResolver.resolveIdentifiersInFilter( null, null );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithEmptyFilter( )
        throws IOException
    {
        filterPatientResolver.resolveIdentifiersInFilter( "", null );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithMissingIdmService( )
        throws IOException, DocumentException
    {
        SinglePatientResolver emptyPatientResolver = new SinglePatientResolver();

        String filterWithNationaId = StreamUtil.resourceToString( new FileSystemResource(
                        "src/test/java/gov/va/med/cds/filter/vhim400/filterWithNationalId.xml" ) );
        
        Document filterRequestDocument = DocumentHelper.parseText( filterWithNationaId );
        
        emptyPatientResolver.resolveIdentifiersInFilter( filterId, filterRequestDocument );
    }


    @Test( expected = FilterPatientResolverException.class )
    @Suite( groups = { "checkintest" } )
    public void testResolveFilterWithBadFilterString( )
        throws IOException
    {
        SinglePatientResolver emptyPatientResolver = new SinglePatientResolver();

        emptyPatientResolver.resolveIdentifiersInFilter( "junkId", null );
    }


    private boolean checkResolvedIdentifiers( String resolvedFilter, int numResolvedIds )
    {
        String resolvedIds = resolvedFilter;
        int i = 0;
        int ix = 0;
        while ( ( ix = resolvedIds.indexOf( "<resolvedIdentifiers>" ) ) >= 0 )
        {
            i++ ;
            resolvedIds = resolvedIds.substring( ix + "<resolvedIdentifiers>".length() );
        }
        return i == numResolvedIds;
    }


    @Resource
    public void setFilterPatientResolver( SinglePatientResolver filterPatientResolver )
    {
        this.filterPatientResolver = filterPatientResolver;
    }
}
