/**
 * 
 */


package gov.va.med.cds.filter;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.request.ValidationException;
import gov.va.med.cds.util.StreamUtil;

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

import java.io.IOException;
import java.util.Calendar;
import java.util.Map;

import javax.annotation.Resource;


/**
 * @author susarlan
 *
 */
@RunWith( SuiteAwareRunner.class )
public class FilterQueryMetadataTest
{
    private static final String TIU_FILTER_ID = "TIU_SINGLE_PATIENT_ALL_DATA_FILTER";

    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadata( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterForParameterMap.xml" );
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "ClinicalDocumentEvent" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 0 );
        assertTrue( filterQueryMetadata.useDates() );

        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.DAY_OF_MONTH ), 12 );

        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.DAY_OF_MONTH ), 16 );

        ParameterMapInterface optionalParams = filterQueryMetadata.getAdditionalParametersMap();
        assertNotNull( optionalParams );
        assertNotNull( optionalParams.getParameterValue( "documentClass" ) );
        assertNull( optionalParams.getParameterValue( "documentType" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWihRecordIdentifiers( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/rxSinglePatientSingleRecordFilter.xml" );
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "OutpatientMedicationPromise" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 1 );
        assertFalse( filterQueryMetadata.useDates() );
        assertNull(filterQueryMetadata.getAdditionalParametersMap());
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWithNoStartDateInFilter( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterForParameterMap.xml" );
        Element startDateElement = entryPointFilterElement.element( "startDate" );
        startDateElement.detach();
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "ClinicalDocumentEvent" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 0 );
        assertTrue( filterQueryMetadata.useDates() );

        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.YEAR ), 1841 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.MONTH ), 0 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.DAY_OF_MONTH ), 1 );

        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.DAY_OF_MONTH ), 16 );

        ParameterMapInterface optionalParams = filterQueryMetadata.getAdditionalParametersMap();
        assertNotNull( optionalParams );
        assertNotNull( optionalParams.getParameterValue( "documentClass" ) );
        assertNull( optionalParams.getParameterValue( "documentType" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWithNoEndDateInFilter( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterForParameterMap.xml" );
        Element endDateElement = entryPointFilterElement.element( "endDate" );
        endDateElement.detach();
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "ClinicalDocumentEvent" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 0 );
        assertTrue( filterQueryMetadata.useDates() );

        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.DAY_OF_MONTH ), 12 );

        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.YEAR ), 3000 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.MONTH ), 11 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.DAY_OF_MONTH ), 31 );

        ParameterMapInterface optionalParams = filterQueryMetadata.getAdditionalParametersMap();
        assertNotNull( optionalParams );
        assertNotNull( optionalParams.getParameterValue( "documentClass" ) );
        assertNull( optionalParams.getParameterValue( "documentType" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWithNoDatesInFilter( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterForParameterMap.xml" );
        Element startDateElement = entryPointFilterElement.element( "startDate" );
        startDateElement.detach();
        Element endDateElement = entryPointFilterElement.element( "endDate" );
        endDateElement.detach();
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "ClinicalDocumentEvent" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 0 );
        assertFalse( filterQueryMetadata.useDates() );

        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.YEAR ), 1841 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.MONTH ), 0 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.DAY_OF_MONTH ), 1 );

        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.YEAR ), 3000 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.MONTH ), 11 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.DAY_OF_MONTH ), 31 );

        ParameterMapInterface optionalParams = filterQueryMetadata.getAdditionalParametersMap();
        assertNotNull( optionalParams );
        assertNotNull( optionalParams.getParameterValue( "documentClass" ) );
        assertNull( optionalParams.getParameterValue( "documentType" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWithNoOptionalParameters( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterForParameterMap.xml" );
        Element optionalParameters = entryPointFilterElement.element( "otherQueryParameters" );
        optionalParameters.detach();
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );

        assertEquals( filterQueryMetadata.getDomainEntryPoint(), "ClinicalDocumentEvent" );
        assertEquals( filterQueryMetadata.getRequestId(), "requestId" );
        assertEquals( filterQueryMetadata.getTemplateId(), "templateId" );
        assertEquals( filterQueryMetadata.getQueryName(), "ID_1" );
        assertTrue( filterQueryMetadata.getRecordIdentifiers().size() == 0 );
        assertTrue( filterQueryMetadata.useDates() );

        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getStartDate().get( Calendar.DAY_OF_MONTH ), 12 );

        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.YEAR ), 1967 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.MONTH ), 7 );
        assertEquals( filterQueryMetadata.getEndDate().get( Calendar.DAY_OF_MONTH ), 16 );

        ParameterMapInterface optionalParams = filterQueryMetadata.getAdditionalParametersMap();
        assertNull( optionalParams );
    }


    @Test( expected = ValidationException.class )
    @Suite( groups = { "checkintest" } )
    public void testFilterQueryMetadataWithInvalidDateFormat( )
    {
        Element entryPointFilterElement = initTiuFilter( "src/test/java/gov/va/med/cds/filter/tiuFilterWithInvalidDate.xml" );
        FilterQueryMetadata filterQueryMetadata = new FilterQueryMetadata( entryPointFilterElement, "templateId", "requestId" );
    }


    private Element initTiuFilter( String fileSystemResource )
    {
        Element entryPointFilterElement = null;
        try
        {
            String tiuFilter = StreamUtil.resourceToString( new FileSystemResource( fileSystemResource ) );
            Document filterDocument = DocumentHelper.parseText( tiuFilter );
            Element rootElement = filterDocument.getRootElement();
            entryPointFilterElement = rootElement.element( "entryPointFilter" );
        }
        catch ( IOException i )
        {
            fail( "Could not get filter xml resource" );
        }
        catch ( DocumentException e )
        {
            fail( "Could not parse tiuFilter" );
        }
        assertNotNull( entryPointFilterElement );
        return entryPointFilterElement;
    }
}
