/**
 * 
 */


package gov.va.med.cds.filter;


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.testharness.logger.AssertApplicationLogger;
import gov.va.med.cds.util.StreamUtil;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;

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;


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


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterNamesWithNoAdditionalParameters( )
    {
        ParameterMap parameterMap = new ParameterMap( null );
        Set<String> queryParameterNames = parameterMap.getFilterParameterNames();
        assertTrue( queryParameterNames.size() == 0 );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValueWithNoAdditionalParameters( )
    {
        ParameterMap parameterMap = new ParameterMap( null );
        QueryParameter<?> queryParameter = parameterMap.getParameterValue( "documentClass" );
        assertNull( queryParameter );
        queryParameter = parameterMap.getParameterValue( "documentType" );
        assertNull( queryParameter );
    }


    private Element initTiuFilter( String filterXml )
        throws IOException
    {
        Element otherParametersElement = null;
        try
        {
            String tiuFilter = StreamUtil.resourceToString( new FileSystemResource( "src/test/java/gov/va/med/cds/filter/" + filterXml ) );
            Document filterDocument = DocumentHelper.parseText( tiuFilter );
            Element rootElement = filterDocument.getRootElement();
            Element entryPointFilterElement = rootElement.element( "entryPointFilter" );
            otherParametersElement = entryPointFilterElement.element( "otherQueryParameters" );
        }
        catch ( DocumentException e )
        {
            fail( "Could not parse tiuFilter" );
        }
        assertNotNull( otherParametersElement );
        return otherParametersElement;
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterNames( )
        throws IOException
    {
        Element otherParametersElement = initTiuFilter( "tiuFilterForParameterMap.xml" );
        ParameterMap parameterMap = new ParameterMap( otherParametersElement );
        Set<String> queryParameterNames = parameterMap.getFilterParameterNames();
        assertNotNull( queryParameterNames );
        assertTrue( queryParameterNames.size() == 2 );
        for ( String parameterName : queryParameterNames )
        {
            QueryParameter<?> queryParameter = parameterMap.getParameterValue( parameterName );
            assertNotNull( queryParameter );
            assertTrue( queryParameter.getName().equals( parameterName ) );
            if ( "documentClass".equals( parameterName ) )
            {
                assertFalse( queryParameter.getValue() instanceof List );
                assertTrue( queryParameter.getValue() instanceof String );
                assertTrue( "3".equals( queryParameter.getValue() ) );
            }
            else if ( "person".equals( parameterName ) )
            {
                assertTrue( queryParameter.getValue() instanceof Map<?, ?> );
                Map<String, Object> paramMap = ( Map<String, Object> )queryParameter.getValue();
                assertTrue( paramMap.containsKey( "person_last" ) );
                assertTrue( paramMap.containsKey( "person_first" ) );
                assertTrue( "aLastName".equals( paramMap.get( "person_last" ) ) );
                assertTrue( "aFirstName".equals( paramMap.get( "person_first" ) ) );

            }
            else
            {
                fail();
            }
        }

        // test after detaching - no additional parameters should exist
        Element documentClassElement = otherParametersElement.element( "documentClass" );
        documentClassElement.detach();
        Element personElement = otherParametersElement.element( "person" );
        personElement.detach();
        parameterMap = new ParameterMap( otherParametersElement );
        queryParameterNames = parameterMap.getFilterParameterNames();
        assertNotNull( queryParameterNames );
        assertTrue( queryParameterNames.size() == 0 );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValue( )
        throws IOException
    {
        Element otherParametersElement = initTiuFilter( "tiuFilterWithDocumentType.xml" );
        ParameterMap parameterMap = new ParameterMap( otherParametersElement );
        Set<String> queryParameterNames = parameterMap.getFilterParameterNames();
        for ( String parameterName : queryParameterNames )
        {
            QueryParameter<?> queryParameter = parameterMap.getParameterValue( parameterName );
            assertNotNull( queryParameter );
            assertTrue( queryParameter.getName().equals( parameterName ) );
            if ( "documentClass".equals( parameterName ) )
            {
                fail();
            }
            else
            {
                assertTrue( queryParameter.getValue() instanceof List );
                assertTrue( ( ( List )queryParameter.getValue() ).size() == 4 );
            }
        }

        // test after detaching
        Element documentClassElement = otherParametersElement.element( "documentType" );
        documentClassElement.detach();
        parameterMap = new ParameterMap( otherParametersElement );

        // default values returned since no documentClass exists in the filter
        QueryParameter<?> queryParameter = parameterMap.getParameterValue( "documentType" );
        assertNotNull( queryParameter );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterNamesWithInvalidElement( )
        throws IOException
    {
        Element otherParametersElement = initTiuFilter( "tiuFilterForParameterMap.xml" );
        Element documentClassElement = otherParametersElement.element( "documentClass" );
        ParameterMap parameterMap = new ParameterMap( documentClassElement );
        Set<String> queryParameterNames = parameterMap.getFilterParameterNames();
        assertNotNull( queryParameterNames );
        assertTrue( queryParameterNames.size() == 0 );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValueWithInvalidElement( )
        throws IOException
    {
        Element otherParametersElement = initTiuFilter( "tiuFilterForParameterMap.xml" );
        Element documentClassElement = otherParametersElement.element( "documentClass" );
        ParameterMap parameterMap = new ParameterMap( documentClassElement );
        Set<String> queryParameterNames = parameterMap.getFilterParameterNames();
        for ( String parameterName : queryParameterNames )
        {
            QueryParameter queryParameter = parameterMap.getParameterValue( parameterName );
            assertNull( queryParameter );
        }
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValueWithInvalidParameterName( )
    {
        ParameterMap parameterMap = new ParameterMap( null );
        assertNull( parameterMap.getParameterValue( "invalidParameterName" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValueWithMissingParameterName( )
    {
        ParameterMap parameterMap = new ParameterMap( null );
        assertNull( parameterMap.getParameterValue( "" ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testGetParameterValueWithNullParameterName( )
    {
        ParameterMap parameterMap = new ParameterMap( null );
        assertNull( parameterMap.getParameterValue( null ) );
    }
}
