/**
 * 
 */


package gov.va.med.cds.internal;


import static org.easymock.EasyMock.createNiceMock;
import static org.junit.Assert.assertNotNull;
import gov.va.med.cds.audit.VhimRequestAuditLoggerInterface;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.clinicaldata.Operation;
import gov.va.med.cds.clinicaldata.TemplateMetaDataInterface;
import gov.va.med.cds.clinicaldata.vhim400.ClinicalDataResponseInterface;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.exceptionframework.ExceptionHandler;
import gov.va.med.cds.exceptionframework.ExceptionLoggerInterface;
import gov.va.med.cds.filter.CdsFilterFactoryInterface;
import gov.va.med.cds.filter.CdsFilterInterface;
import gov.va.med.cds.filter.FilterPatientResolverInterface;
import gov.va.med.cds.junit.runners.PowerMockSuiteAwareRunner;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.persistence.PersistenceException;
import gov.va.med.cds.request.ErrorSectionHelperInterface;
import gov.va.med.cds.response.PatientIdentifierDocumentBuilderInterface;
import gov.va.med.cds.response.WriteResponseGeneratorInterface;
import gov.va.med.cds.template.TemplateHelperInterface;
import gov.va.med.cds.template.TemplateManager;
import gov.va.med.cds.transaction.TransactionManagerInterface;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
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.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;


/**
 * @author susarlan
 *
 */
@RunWith( PowerMockSuiteAwareRunner.class )
@PrepareForTest( { DocumentHelper.class} )

public class ClinicalDataServiceSynchronousInternalTest
{
    public static String WRITE_REQUEST = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                    + "<clinicaldata:ClinicalData xsi:schemaLocation=\"Clinicaldata IntoleranceConditionCreate40020.xsd\" xmlns:clinicaldata=\"Clinicaldata\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
                    + "<templateId>IntoleranceConditionCreate40020</templateId>" + "<patient/></clinicaldata:ClinicalData>";

    private ClinicalDataServiceSynchronousInternal cdsInternal;
    private TransactionManagerInterface transactionManager;

    private CdsFilterFactoryInterface filterFactory;
    private FilterPatientResolverInterface filterPatientResolver;
    private TemplateManager templateManager;
    private TemplateHelperInterface templateHelper;
    private VhimRequestAuditLoggerInterface vhimRequestAuditLogger;

    private WriteResponseGeneratorInterface writeResponseGenerator;
    private ErrorSectionHelperInterface errorSectionHelper;
    private ExceptionLoggerInterface guaranteedLogger;
    private ClinicalDataResponseInterface clinicalDataResponse;
    private PatientIdentifierDocumentBuilderInterface patientIdentifierDocBuilder;

    @Suite( groups = { "checkintest" } )
    private void initMocks( )
        throws Exception
    {
        transactionManager = EasyMock.createMock( TransactionManagerInterface.class );
        filterFactory = EasyMock.createNiceMock( CdsFilterFactoryInterface.class );
        filterPatientResolver = EasyMock.createNiceMock( FilterPatientResolverInterface.class );
        templateManager = EasyMock.createMock( TemplateManager.class );
        templateHelper = EasyMock.createNiceMock( TemplateHelperInterface.class );
        vhimRequestAuditLogger = EasyMock.createMock( VhimRequestAuditLoggerInterface.class );
        patientIdentifierDocBuilder = EasyMock.createMock( PatientIdentifierDocumentBuilderInterface.class );

        cdsInternal = new ClinicalDataServiceSynchronousInternal();
        cdsInternal.setTransactionManager( transactionManager );
        cdsInternal.setFilterFactory( filterFactory );
        cdsInternal.setFilterPatientResolver( filterPatientResolver );
        cdsInternal.setTemplateManager( templateManager );
        cdsInternal.setTemplateHelper( templateHelper );

        writeResponseGenerator = createNiceMock( WriteResponseGeneratorInterface.class );

        guaranteedLogger = createNiceMock( ExceptionLoggerInterface.class );
        errorSectionHelper = createNiceMock( ErrorSectionHelperInterface.class );
        clinicalDataResponse = createNiceMock( ClinicalDataResponseInterface.class );
        ExceptionHandler.setGuaranteedLogger( guaranteedLogger );
        ExceptionHandler.setTemplateHelper( templateHelper );
        ExceptionHandler.setClinicalDataResponse( clinicalDataResponse );
    }


    /**   * Called before each test.   */
    @Before
    @Suite( groups = { "checkintest" } )
    public void setUp( )
        throws Exception
    {
        initMocks();
        EasyMock.reset( transactionManager );
        EasyMock.reset( filterFactory );
        EasyMock.reset( filterPatientResolver );
        EasyMock.reset( templateManager );
        EasyMock.reset( templateHelper );
        EasyMock.reset( vhimRequestAuditLogger );
        EasyMock.reset( patientIdentifierDocBuilder );

        EasyMock.reset( writeResponseGenerator );
        EasyMock.reset( guaranteedLogger );
        EasyMock.reset( errorSectionHelper );
        EasyMock.reset( clinicalDataResponse );

    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testReadClinicalDataDocument( )
        throws Exception
    {
        String filterId = "FilterId";
        String templateId = "TemplateId";
        String requestId = "RequestId";

        String vhimVersion = "vhim_4_00";

        String filterRequest = "FilterRequest";

        Document filterRequestDocument = PowerMock.createMock( Document.class );
        Element rootElement = EasyMock.createMock( Element.class );
        Element entryPointElement = EasyMock.createMock( Element.class );
        // PowerMock for Static
        PowerMock.mockStaticPartial( DocumentHelper.class, "parseText" );

        EasyMock.expect(DocumentHelper.parseText( filterRequest ) ).andReturn( filterRequestDocument );
        EasyMock.expect(filterRequestDocument.getRootElement()).andReturn( rootElement );
        EasyMock.expect(rootElement.element("entryPointFilter")).andReturn( entryPointElement );
        EasyMock.expect(entryPointElement.attributeValue( "isPatientCentric")).andReturn( "true" );

        EasyMock.expect( filterPatientResolver.resolveIdentifiersInFilter( EasyMock.eq( filterId ), EasyMock.eq( filterRequestDocument ) ) )
                        .andReturn( filterRequestDocument );

        CdsFilterInterface cdsFilter = EasyMock.createNiceMock( CdsFilterInterface.class );

        EasyMock.expect(
                        filterFactory.create( EasyMock.eq( filterId ), EasyMock.eq( filterRequestDocument ), EasyMock.eq( templateId ),
                                        EasyMock.eq( requestId ) ) ).andReturn( cdsFilter );
        EasyMock.expect( cdsFilter.getVhimVersion() ).andReturn( vhimVersion );
        
        Set<String> domainEntryPoints = new HashSet<String>();
        EasyMock.expect( cdsFilter.getDomainEntryPoints() ).andReturn( domainEntryPoints );

        TemplateMetaDataInterface templateMetaData = EasyMock.createNiceMock( TemplateMetaDataInterface.class );
        Set<DomainEntryPoint> entryPoints = new HashSet<DomainEntryPoint>();
        EasyMock.expect( templateMetaData.getDomainEntryPoints() ).andReturn( entryPoints );

        EasyMock.expect( transactionManager.performReadOnClinicalData( EasyMock.eq( templateId ), EasyMock.eq( requestId ), EasyMock.eq( cdsFilter ) ) )
                        .andReturn( new ArrayList<Document>() );
        EasyMock.expect( templateHelper.getPatientIdentifierDocumentBuilder( EasyMock.eq( templateId ) ) ).andReturn( patientIdentifierDocBuilder );
        EasyMock.expect(
                        patientIdentifierDocBuilder.createPatientWithIdentifiersDocument( EasyMock.eq( cdsFilter ), EasyMock.eq( templateId ),
                                        EasyMock.eq( requestId ) ) ).andReturn( DocumentHelper.createDocument() );

        EasyMock.expect( templateManager.validateReadTemplateId( templateId ) ).andReturn( templateMetaData );

        PowerMock.replay( filterPatientResolver, cdsFilter, filterFactory, transactionManager, templateMetaData, templateManager, templateHelper,
                        patientIdentifierDocBuilder, DocumentHelper.class, filterRequestDocument, rootElement );

        List<Document> results = cdsInternal.readClinicalData( filterRequest, filterId, templateId, requestId );
        assertNotNull( results );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testCreateClinicalDataDocument( )
    {
        String request = WRITE_REQUEST;
        String templateId = "TemplateId";
        String requestId = "RequestId";

        Element recordIdentifierElementMock = EasyMock.createNiceMock( Element.class );
        List<Element> createdRecordIdentifiers = new ArrayList<Element>();
        createdRecordIdentifiers.add( recordIdentifierElementMock );

        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Create ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andReturn( createdRecordIdentifiers );
        EasyMock.expect( templateHelper.getWriteResponseGenerator( templateId ) ).andReturn( writeResponseGenerator );
        EasyMock.expect( writeResponseGenerator.generateSuccessfulWriteResponse( templateId, requestId, createdRecordIdentifiers ) ).andReturn(
                        DocumentHelper.createDocument() );

        EasyMock.replay( transactionManager, templateHelper, writeResponseGenerator );

        Map<String, String> namespacesMap = new HashMap();
        namespacesMap.put( "HealthAdapterCreate1", "patientjournaling:" );

        cdsInternal.setNamespacesMap( namespacesMap );
        Document doc = cdsInternal.createClinicalData( request, templateId, requestId );
        assertNotNull( doc );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testUpdateClinicalDataDocument( )
    {
        String request = WRITE_REQUEST;
        String templateId = "TemplateId";
        String requestId = "RequestId";

        Element recordIdentifierElementMock = EasyMock.createNiceMock( Element.class );
        List<Element> createdRecordIdentifiers = new ArrayList<Element>();
        createdRecordIdentifiers.add( recordIdentifierElementMock );

        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Update ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andReturn( createdRecordIdentifiers );
        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Update ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andReturn( createdRecordIdentifiers );
        EasyMock.expect( templateHelper.getWriteResponseGenerator( templateId ) ).andReturn( writeResponseGenerator );
        EasyMock.expect( writeResponseGenerator.generateSuccessfulWriteResponse( templateId, requestId, createdRecordIdentifiers ) ).andReturn(
                        DocumentHelper.createDocument() );

        EasyMock.replay( transactionManager, templateHelper, writeResponseGenerator );

        Map<String, String> namespacesMap = new HashMap();
        namespacesMap.put( "HealthAdapterUpdate1", "patientjournaling:" );

        cdsInternal.setNamespacesMap( namespacesMap );
        Document doc = cdsInternal.updateClinicalData( request, templateId, requestId );
        assertNotNull( doc );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testUpdateClinicalDataDocumentErrorCondition( )
    {
        String request = WRITE_REQUEST;
        String templateId = "TemplateId";
        String requestId = "RequestId";
        String appName = "CdsAppName";
        PersistenceException ex = new PersistenceException( ErrorCodeEnum.CANNOT_LOAD_FILTER_SCHEMA_FROM_PERSISTENCE );

        Element recordIdentifierElementMock = EasyMock.createNiceMock( Element.class );
        List<Element> createdRecordIdentifiers = new ArrayList<Element>();
        createdRecordIdentifiers.add( recordIdentifierElementMock );

        EasyMock.expect( templateHelper.getWriteResponseGenerator( templateId ) ).andReturn( writeResponseGenerator );
        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Create ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andThrow( ex );
        EasyMock.expect(
                        writeResponseGenerator.generateWriteErrorResponse( EasyMock.eq( templateId ), EasyMock.eq( requestId ), EasyMock.eq( ex ),
                                        EasyMock.isA( Document.class ), EasyMock.eq( appName ) ) ).andReturn( DocumentHelper.createDocument() );

        EasyMock.replay( transactionManager, templateHelper, writeResponseGenerator );

        Map<String, String> namespacesMap = new HashMap();
        namespacesMap.put( "HealthAdapterUpdate1", "patientjournaling:" );

        cdsInternal.setNamespacesMap( namespacesMap );
        cdsInternal.doCUAD( Operation.Create, request, templateId, requestId );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testDeleteClinicalDataDocument( )
    {
        String request = WRITE_REQUEST;
        String templateId = "TemplateId";
        String requestId = "RequestId";

        Element recordIdentifierElementMock = EasyMock.createNiceMock( Element.class );
        List<Element> createdRecordIdentifiers = new ArrayList<Element>();
        createdRecordIdentifiers.add( recordIdentifierElementMock );

        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Delete ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andReturn( createdRecordIdentifiers );
        EasyMock.expect( templateHelper.getWriteResponseGenerator( templateId ) ).andReturn( writeResponseGenerator );
        EasyMock.expect( writeResponseGenerator.generateSuccessfulWriteResponse( templateId, requestId, createdRecordIdentifiers ) ).andReturn(
                        DocumentHelper.createDocument() );

        EasyMock.replay( transactionManager, templateHelper, writeResponseGenerator );

        Map<String, String> namespacesMap = new HashMap();
        namespacesMap.put( "HealthAdapterDelete1", "patientjournaling:" );

        cdsInternal.setNamespacesMap( namespacesMap );
        Document doc = cdsInternal.deleteClinicalData( request, templateId, requestId );
        assertNotNull( doc );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testAppendClinicalDataDocument( )
    {
        String request = WRITE_REQUEST;
        String templateId = "TemplateId";
        String requestId = "RequestId";

        Element recordIdentifierElementMock = EasyMock.createNiceMock( Element.class );
        List<Element> createdRecordIdentifiers = new ArrayList<Element>();
        createdRecordIdentifiers.add( recordIdentifierElementMock );

        EasyMock.expect(
                        transactionManager.performCUADOnClinicalData( EasyMock.eq( Operation.Append ), EasyMock.isA( Document.class ),
                                        EasyMock.eq( templateId ), EasyMock.eq( requestId ) ) ).andReturn( createdRecordIdentifiers );
        EasyMock.expect( templateHelper.getWriteResponseGenerator( templateId ) ).andReturn( writeResponseGenerator );
        EasyMock.expect( writeResponseGenerator.generateSuccessfulWriteResponse( templateId, requestId, createdRecordIdentifiers ) ).andReturn(
                        DocumentHelper.createDocument() );

        EasyMock.replay( transactionManager, templateHelper, writeResponseGenerator );

        Map<String, String> namespacesMap = new HashMap();
        namespacesMap.put( "HealthAdapterCreate1", "patientjournaling:" );

        cdsInternal.setNamespacesMap( namespacesMap );
        Document doc = cdsInternal.appendClinicalData( request, templateId, requestId );
        assertNotNull( doc );
    }
}
