/**
 * 
 */


package gov.va.med.cds.persistence.hibernate;


import gov.va.med.cds.clinicaldata.ClinicalRecordInterface;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.clinicaldata.Operation;
import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.persistence.AbstractPersistenceManager;
import gov.va.med.cds.persistence.PersistenceException;
import gov.va.med.cds.persistence.PersistenceManagerInterface;
import gov.va.med.cds.rules.BooleanRuleInterface;
import gov.va.med.cds.template.generated.JaxBMarshallerUnmarshaller;
import gov.va.med.cds.template.generated.JaxBMarshallerUnmarshallerInterface;
import gov.va.med.cds.template.generated.allergies.AllergyAssessment;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.easymock.EasyMock;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author vhaislegberb
 *
 */
@RunWith( SuiteAwareRunner.class )
public class WriteableHibernatePersistenceManagerTest
{

    @Test
    @Suite( groups = { "checkintest" } )
    public void testSetGetManagerIdentifier( )
        throws Exception
    {
        PersistenceManagerInterface persistenceManager = new WriteableHibernatePersistenceManager();
        ( ( AbstractPersistenceManager )persistenceManager ).setManagerIdentifier( "managerIdentifier1" );
        Assert.assertEquals( "managerIdentifier1", persistenceManager.getManagerIdentifier() );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testIsApplicableFalse( )
    {
        List<BooleanRuleInterface> rules = new ArrayList<BooleanRuleInterface>();

        Object criteria = "criteria";

        BooleanRuleInterface rule1 = EasyMock.createMock( BooleanRuleInterface.class );
        EasyMock.expect( rule1.evaluate( criteria ) ).andReturn( Boolean.FALSE );
        BooleanRuleInterface rule2 = EasyMock.createMock( BooleanRuleInterface.class );
        EasyMock.expect( rule2.evaluate( criteria ) ).andReturn( Boolean.FALSE );
        EasyMock.replay( rule1, rule2 );

        rules.add( rule1 );
        rules.add( rule2 );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setRules( rules );

        Assert.assertFalse( persistenceManager.isApplicable( criteria ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testIsApplicableTrue( )
    {
        List<BooleanRuleInterface> rules = new ArrayList<BooleanRuleInterface>();

        Object criteria = "criteria";

        BooleanRuleInterface rule1 = EasyMock.createMock( BooleanRuleInterface.class );
        EasyMock.expect( rule1.evaluate( criteria ) ).andReturn( Boolean.FALSE );
        BooleanRuleInterface rule2 = EasyMock.createMock( BooleanRuleInterface.class );
        EasyMock.expect( rule2.evaluate( criteria ) ).andReturn( Boolean.TRUE );
        EasyMock.replay( rule1, rule2 );

        rules.add( rule1 );
        rules.add( rule2 );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setRules( rules );

        Assert.assertTrue( persistenceManager.isApplicable( criteria ) );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testPerformCUADOnClinicalDataCreate( ) throws Exception
    {
        String templateId = "theTemplateId";
        Element theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        ClinicalRecordInterface unmarshalledObject = unmarshallObject(theObject,DomainEntryPoint.AllergyAssessment );
        
        Session session = EasyMock.createMock( Session.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = EasyMock.createMock(JaxBMarshallerUnmarshallerInterface.class);
        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.expect(marshallerUnmarshaller.unmarshal(theObject, AllergyAssessment.class)).andReturn(unmarshalledObject).andThrow(new Exception());
        EasyMock.expect( session.save( unmarshalledObject ) ).andReturn( 101 );
        session.flush();
        EasyMock.replay( sessionFactory, session, marshallerUnmarshaller );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Create, theObject, DomainEntryPoint.AllergyAssessment );

    }
    
    private Element createDomElement(DomainEntryPoint domainEntryPoint){
    	
    	Element clinicalRecord = DocumentHelper.createElement( domainEntryPoint.getEntityName() );
    	Element patient = DocumentHelper.createElement( "patient" );
    	Element identifier = DocumentHelper.createElement( "identifier" );
    	Element identity = DocumentHelper.createElement( "identity" );
    	identity.setText("9999TEST");
        identifier.add(identity);
        patient.add(identifier);
        clinicalRecord.add( patient );
    	
        return clinicalRecord;
    }


    @Test( expected = HibernateConstraintViolationException.class )
    @Suite( groups = { "checkintest" } )
    public void testPerformCUADOnClinicalDataCreateDuplicate( ) throws Exception
    {
        String templateId = "theTemplateId";
        
        Element theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        ClinicalRecordInterface unmarshalledObject = unmarshallObject(theObject,DomainEntryPoint.AllergyAssessment );
        
        Session session = EasyMock.createMock( Session.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = EasyMock.createMock(JaxBMarshallerUnmarshallerInterface.class);
        
        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.expect(marshallerUnmarshaller.unmarshal(theObject, AllergyAssessment.class)).andReturn(unmarshalledObject).andThrow(new Exception());
        EasyMock.expect( session.save( unmarshalledObject ) ).andThrow(
                        new ConstraintViolationException( "Constraint violated!", new SQLException( "Duplicate constraint 'foo.bar' violated." ),
                                        "foo.bar" ) );
        session.flush();
        EasyMock.replay( sessionFactory, session, marshallerUnmarshaller  );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Create, theObject, DomainEntryPoint.AllergyAssessment );

    }


    @Test( expected = PersistenceException.class )
    @Suite( groups = { "checkintest" } )
    public void testPerformCUADOnClinicalDataCreatePersistenceException( ) throws Exception
    {
        String templateId = "theTemplateId";
        Element theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        ClinicalRecordInterface unmarshalledObject = unmarshallObject(theObject,DomainEntryPoint.AllergyAssessment );
        
   
        Session session = EasyMock.createMock( Session.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = EasyMock.createMock(JaxBMarshallerUnmarshallerInterface.class);
        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.expect(marshallerUnmarshaller.unmarshal(theObject, AllergyAssessment.class)).andReturn(unmarshalledObject).andThrow(new Exception());
        EasyMock.expect( session.save( unmarshalledObject ) ).andThrow( new PersistenceException( ErrorCodeEnum.CANNOT_SAVE_TEMPLATE ) );
        session.flush();
        EasyMock.replay( sessionFactory, session, marshallerUnmarshaller );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Create, theObject, DomainEntryPoint.AllergyAssessment );

    }


    //@Test ( expected = PersistenceException.class )
    @Suite( groups = { "brokentest" } )
    public void testPerformCUADOnClinicalDataUpdate( )
    {
        String templateId = "theTemplateId";
        Object theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        //String domainEntryPoint = "theDomainEntryPoint";

        Session session = EasyMock.createMock( Session.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.replay( sessionFactory, session );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller= new JaxBMarshallerUnmarshaller();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Update, theObject, DomainEntryPoint.AllergyAssessment );

    }


    @Test( expected = PersistenceException.class )
    @Suite( groups = { "checkintest" } )
    public void testPerformCUADOnClinicalDataAppend( )
    {
        String templateId = "theTemplateId";
        Object theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        //String domainEntryPoint = "theDomainEntryPoint";

        Session session = EasyMock.createMock( Session.class );
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.replay( sessionFactory, session );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller= new JaxBMarshallerUnmarshaller();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Append, theObject, DomainEntryPoint.AllergyAssessment );

    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testPerformCUADOnClinicalDataDelete( ) throws Exception
    {
        String templateId = "theTemplateId";
        Element theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        ClinicalRecordInterface unmarshalledObject = unmarshallObject(theObject,DomainEntryPoint.AllergyAssessment );
        
        SessionFactory sessionFactory = EasyMock.createMock( SessionFactory.class );
        Session session = EasyMock.createMock( Session.class );
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = EasyMock.createMock(JaxBMarshallerUnmarshallerInterface.class);
        Criteria criteria = EasyMock.createNiceMock( Criteria.class );
        List readResults = EasyMock.createMock( List.class );
        Map<String, String> logicalDeleteTemplateIdsMap = new HashMap();

        EasyMock.expect( sessionFactory.getCurrentSession() ).andReturn( session );
        EasyMock.expect(marshallerUnmarshaller.unmarshal(theObject, AllergyAssessment.class)).andReturn(unmarshalledObject).andThrow(new Exception());
        EasyMock.expect( session.createCriteria( String.class ) ).andReturn( criteria );
        EasyMock.expect( criteria.add( EasyMock.createMock( Criterion.class ) ) ).andReturn( criteria );
        EasyMock.expect( criteria.list() ).andReturn( readResults );
        EasyMock.expect( readResults.size() ).andReturn( 1 );
        EasyMock.expect( readResults.get( 0 ) ).andReturn( theObject );
        session.delete( unmarshalledObject );
        session.flush();

        EasyMock.replay( sessionFactory, session, marshallerUnmarshaller, criteria, readResults );

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, sessionFactory );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        logicalDeleteTemplateIdsMap.put( "HealthAdapterDelete1", "recordStatus" );
        persistenceManager.setLogicalDeleteTemplateIdsMap( logicalDeleteTemplateIdsMap );
        persistenceManager.performCUADOnClinicalData( templateId, Operation.Delete, theObject, DomainEntryPoint.AllergyAssessment );

    }


    @Test( expected = PersistenceException.class )
    @Suite( groups = { "checkintest" } )
    public void testInvalidTemplateIdPersistenceException( )
    {
        String templateId = "theTemplateId";
        String invalidTemplateId = "invalidTemplateId";
        Object theObject = createDomElement(DomainEntryPoint.AllergyAssessment);
        //String domainEntryPoint = "theDomainEntryPoint";

        Map<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
        sessionFactoryMap.put( templateId, EasyMock.createMock( SessionFactory.class ) );

        WriteableHibernatePersistenceManager persistenceManager = new WriteableHibernatePersistenceManager();
        JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller= new JaxBMarshallerUnmarshaller();
        persistenceManager.setMarshallerUnmarshaller(marshallerUnmarshaller);
        
        persistenceManager.setSessionFactoryMap( sessionFactoryMap );
        persistenceManager.performCUADOnClinicalData( invalidTemplateId, Operation.Delete, theObject, DomainEntryPoint.AllergyAssessment );
    }
    
    private ClinicalRecordInterface unmarshallObject(Element element, DomainEntryPoint domainEntryPoint){
    	try{
    		JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller = new JaxBMarshallerUnmarshaller();
    		return marshallerUnmarshaller.unmarshal(element, domainEntryPoint.getTemplateUnmarshalClass());
    	}
    	catch(Exception e){
    		Assert.fail();
    	}
    	return null;
    }

}
