/**
 * 
 */


package gov.va.med.cds.socket.server.handler;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.hapi.HL7SupportHAPI;
import gov.va.med.cds.hapi.HL7SupportInterface;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.testharness.AbstractBaseTest;
import gov.va.med.cds.util.StreamUtil;

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

import javax.annotation.Resource;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.FileSystemResource;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;


/**
 * @author susarlan
 * 
 */
@RunWith( SuiteAwareSpringRunner.class )
@ContextConfiguration( locations = { "file:src/test/resources/mllpAccessValidatorSpringContext.xml" } )
public class MllpAccessValidatorTest
    extends
        AbstractBaseTest
{
    private MllpAccessValidator mllpAccessValidator;

    private Map <String, Map<String, List<String>>> allowableParameterValues;


    @Resource
    public void setAllowableParameterValues( Map <String, Map<String, List<String>>> allowableParameterValues )
    {
        this.allowableParameterValues = allowableParameterValues;
    }


    @Resource
    public void setMllpAccessValidator( MllpAccessValidator mllpAccessValidator )
    {
        this.mllpAccessValidator = mllpAccessValidator;
    }


    /***
     * Process onData on the data handler without setting up an access validator
     * - test and ensure that the default validator is kicked in (should not get
     * a null pointer exception when MllpDataHandle's onData is invoked w/o
     * setting up an access validator.
     * 
     */
    /* @Test
     @Suite(groups = "checkintest")
     public void testNullAccessValidator( )
         throws Exception
     {
         // Set up mock object for non blocking connection
         INonBlockingConnection nbcMock = ( INonBlockingConnection )createNiceMock( INonBlockingConnection.class );

         // Create request
         String hl7Request = StreamUtil.resourceToString( new FileSystemResource( "./src/test/resources/chdr-allergies.rpc" ) );
         ByteBuffer reqBuffer = MllpUtil.encode( ByteBuffer.wrap( hl7Request.getBytes() ) );

         expect( nbcMock.readByteBufferByDelimiter( isA( String.class ) ) ).andReturn( new ByteBuffer[] { reqBuffer } );
         expect( nbcMock.write( isA( ByteBuffer.class ) ) ).andReturn( 0 );
         nbcMock.flush();

         // Set up mock object for message mediator
         MessageMediatorDispatcherInterface messageMediatorDispatcher = createNiceMock( MessageMediatorDispatcherInterface.class);
         expect( messageMediatorDispatcher.dispatch( isA(HL7SupportInterface.class) )).andReturn( "responseString" );
         
         ResponseGeneratorInterface responseGenerator = createNiceMock( ResponseGeneratorInterface.class );
         expect( responseGenerator.createResponse( isA(HL7SupportInterface.class), EasyMock.eq( "responseString" ), null )).andReturn( "error message");

         MllpMessageMediatorDataHandler dataHandler = new MllpMessageMediatorDataHandler();
         dataHandler.setDispatcher( messageMediatorDispatcher );
         dataHandler.setResponseGenerator( responseGenerator );

         // do not set up the access validator - allow to default to the default
         // validator
         replay( nbcMock, messageMediatorDispatcher, responseGenerator );

         dataHandler.onData( nbcMock );

     }*/

    /***
     * Test validateMessage on MllpMessageValidator
     */
    @Test
    @Suite( groups = "checkintest" )
    public void testValidateAccess( )
        throws Exception
    {
        String hl7Request = StreamUtil.resourceToString( new FileSystemResource( "./src/test/resources/chdr-allergies.rpc" ) );
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    /***
     * Test validateMessage on MllpMessageValidator with missing sending
     * facility
     */
    @Test
    @Suite( groups = "checkintest" )
    public void testValidateAccessWithMissingSendingFacility( )
        throws Exception
    {
        String hl7Request = StreamUtil.resourceToString( new FileSystemResource( "./src/test/resources/chdr-allergies-missing-msh4.rpc" ) );
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    @DirtiesContext
    @Test
    @Suite( groups = "checkintest" )
    public void testValidateAccessNullSpec( )
        throws Exception
    {
        Map <String, Map<String, List<String>>> appContextAllowableParameterValues = this.allowableParameterValues;

        Map<String, List<String>> allowableParameterValuesChdr = new HashMap<String, List<String>>();
        allowableParameterValuesChdr.put( "key", null );
        allowableParameterValues.put( "CHDR", allowableParameterValuesChdr );

        mllpAccessValidator.setAllowableParameterValues( allowableParameterValues);

        String hl7Request = StreamUtil.resourceToString( new FileSystemResource( "./src/test/resources/chdr-allergies.rpc" ) );
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );

        try
        {
            mllpAccessValidator.validateAccess( hl7Support );
        }
        catch ( AccessValidatorException e )
        {
            mllpAccessValidator.setAllowableParameterValues( appContextAllowableParameterValues );
            assertNotNull( e );
            assertEquals( ErrorCodeEnum.HL7_SUPPORT_HAPI_TERSE_EXCEPTION, e.getErrorCode() );
        }
    }


    /***
     * Test for invalid facility from validateMessage on MllpMessageValidator
     */
    @Test( expected = AccessValidatorException.class )
    @Suite( groups = "checkintest" )
    public void testValidateAccessInvalidSendingApplication( )
    {
        String hl7Request = "MSH^~|\\&^HDR^CHDR SENDER^VHA_HDR^INVALID_FACILITY^20080620150649.582-0400~D^^QBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    /***
     * Test for invalid facility from validateMessage on MllpMessageValidator
     * MSH-6 is not a required field for validation
     */
    @Test
    @Suite( groups = "checkintest" )
    public void testValidateAccessInvalidFacility( )
    {
        String hl7Request = "MSH^~|\\&^CHDR SENDER^CHDR^VHA_HDR^INVALID_FACILITY^20080620150649.582-0400~D^^QBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    /***
     * Test for invalid message type from validateMessage on
     * MllpMessageValidator
     */
    @Test( expected = AccessValidatorException.class )
    @Suite( groups = "checkintest" )
    public void testValidateAccessInvalidMessageType( )
    {
        String hl7Request = "MSH^~|\\&^CHDR SENDER^CHDR^VHA_HDR^CHDR^20080620150649.582-0400~D^^BBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testHL7LABMsg_NoValidationExceptions1( )
    {
        /*  
        REQ 1 Sending Applications (MSH-3)- LA7LAB
        REQ 2 Receiving Application (MSH-5) LA7HDR
        REQ 3 Message Type (MSH-9) ORU
        REQ 4 Message Processing ID (MSH-11) P
        REQ 5 Version (MSH-12) 2.4
        */
        String hl7Request = "MSH|^~\\&|LA7LAB|^^DNS|LA7HDR|200HD^HDR.MED.DNS   ^DNS|20020921133629-0500||ORU^R01^ORU_R01|12345678|P|2.4|||NE|NE|USA\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        Assert.assertNotNull( hl7Support );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testHL7LABMsg_NoValidationExceptions2( )
    {
        /*  
        REQ 1 Sending Applications (MSH-3)- LA7LAB
        REQ 2 Receiving Application (MSH-5) LA7HDR
        REQ 3 Message Type (MSH-9) ORU
        REQ 4 Message Processing ID (MSH-11) T
        REQ 5 Version (MSH-12) 2.4
        */
        String hl7Request = "MSH|^~\\&|LA7LAB|^^DNS|LA7HDR|200HD^HDR.MED.DNS   ^DNS|20020921133629-0500||ORU^R01^ORU_R01|12345678|T|2.4|||NE|NE|USA\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        Assert.assertNotNull( hl7Support );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testCHDR_NoValidationExceptions1( )
    {
        /*
        REQ 1 Sending Applications (MSH-3)- CHDR
        REQ 2 Message Type (MSH-9) QBP
         */
        String hl7Request = "MSH^~|\\&^CHDR SENDER^CHDR^VHA_HDR^DNS^20080620150649.582-0400~D^^QBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        Assert.assertNotNull( hl7Support );
        mllpAccessValidator.validateAccess( hl7Support );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testCHDR_NoValidationExceptions2( )
    {
        /*
        REQ 1 Sending Applications (MSH-3)- CHDR SENDER
        REQ 2 Message Type (MSH-9) QBP
         */
        String hl7Request = "MSH^~|\\&^CHDR SENDER^CHDR^VHA_HDR^DNS^20080620150649.582-0400~D^^QBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        Assert.assertNotNull( hl7Support );
        mllpAccessValidator.validateAccess( hl7Support );
    }
    
    @Test (expected = AccessValidatorException.class )
    @Suite( groups = "checkintest" )
    public void testNotCHDRorLAB_MessageException( )
    {
        String hl7Request = "MSH^~|\\&^CHDR2^CHDR^VHA_HDR^DNS^20080620150649.582-0400~D^^QBP~Z99~QRY_Q01^1213988809582^T^2.4\n";
        HL7SupportInterface hl7Support = HL7SupportHAPI.createTranslationSupport( hl7Request );
        Assert.assertNotNull( hl7Support );
        mllpAccessValidator.validateAccess( hl7Support );
    }

}
