

package gov.va.med.cds.filter;


import gov.va.med.cds.clinicaldata.DomainEntryPointWrapper;
import gov.va.med.cds.clinicaldata.EntryFilter;
import gov.va.med.cds.clinicaldata.FilterMetaData;
import gov.va.med.cds.clinicaldata.FilterMetaDataInterface;
import gov.va.med.cds.clinicaldata.VhimVersionWrapper;
import gov.va.med.cds.exception.FilterCacheException;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareRunner;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.easymock.EasyMock;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;


@RunWith( SuiteAwareRunner.class )
public class HibernateOracleFilterCachePersistenceTest
{

    private SessionFactory sessionFactoryMock = EasyMock.createMock( SessionFactory.class );
    private Session sessionMock = EasyMock.createMock( Session.class );
    private Query queryMock = EasyMock.createMock( Query.class );

    HibernateOracleFilterCachePersistence cachePersistence = null;
    protected boolean calledPersistifyVhimVersions;
    protected Object calledPersistifyDomainEntryPoints;
    protected boolean calledPersistifyDomainEntryPoint;
    protected DomainEntryPointWrapper domainEntryPointWrapper;


    @Before
    @Suite( groups = "checkintest" )
    public void beforeHibernateOracleFilterCachePersistenceTestSetUp( )
    {
        EasyMock.reset( sessionFactoryMock, sessionMock, queryMock );

        domainEntryPointWrapper = new DomainEntryPointWrapper();
        domainEntryPointWrapper.setDomain( "Vitals" );
        domainEntryPointWrapper.setName( "Name" );

        //Override Methods from base abstract class - AbstractTfsHibernatePersistenceManager 
        //tested in AbstractTfsHibernatePersistenceManagerTest
        cachePersistence = new HibernateOracleFilterCachePersistence()
        {
            @Override
            protected void persistifyVhimVersions( org.hibernate.Session session, Set<VhimVersionWrapper> vhimVersions )
            {
            }


            @Override
            protected void persistifyDomainEntryPoints( org.hibernate.Session session, Set<DomainEntryPointWrapper> domainEntryPoints )
            {
            }


            @Override
            protected DomainEntryPointWrapper persistifyDomainEntryPoint( org.hibernate.Session session, DomainEntryPointWrapper domainEntryPoint )
            {
                return domainEntryPointWrapper;
            }
        };

        cachePersistence.setSessionFactory( sessionFactoryMock );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testGetFilterIdentifiers( )
    {
        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaIdsByStatus" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "status", "ACTIVE" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.list() ).andReturn( new ArrayList<String>() );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        Assert.assertNotNull( cachePersistence.getFilterIdentifiers() );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );
    }


    @Test ( expected = AssertionError.class )
    @Suite( groups = "checkintest" )
    // Static ExceptionHandler need to be injected, so expecting AssertionError
    public void testGetFilterIdentifiers_ThrowsException( )
    {
        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaIdsByStatus" ) ).andThrow( new HibernateException( "Boom!" ) );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testReplaceFilterPersistence( )
    {

        Criteria criteriaMock = EasyMock.createMock( Criteria.class );
        FilterMetaData filterMetaDataMock = EasyMock.createMock( FilterMetaData.class );
        EntryFilter entryFilterMock = EasyMock.createMock( EntryFilter.class );

        List<FilterMetaDataInterface> filterMetaDatas = new ArrayList<FilterMetaDataInterface>();
        filterMetaDatas.add( filterMetaDataMock );

        Set<EntryFilter> entryFiltersSet = new HashSet<EntryFilter>();
        entryFiltersSet.add( entryFilterMock );

        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        EasyMock.expect( sessionMock.createCriteria( FilterMetaData.class ) ).andReturn( criteriaMock );
        EasyMock.expect( criteriaMock.list() ).andReturn( filterMetaDatas );
        sessionMock.delete( EasyMock.isA( FilterMetaData.class ) );
        sessionMock.flush();

        //persistifyEntryFilters
        EasyMock.expect( filterMetaDataMock.getVhimVersionWrappers() ).andReturn( new HashSet<VhimVersionWrapper>() );
        EasyMock.expect( filterMetaDataMock.getEntryFilters() ).andReturn( entryFiltersSet );

        //persistifyDomainEntryPoint
        entryFilterMock.setDomainEntryPointWrapper( EasyMock.isA( DomainEntryPointWrapper.class ) );
        EasyMock.expect( sessionMock.getNamedQuery( "EntryFilterDomainXpath" ) ).andReturn( queryMock );
        EasyMock.expect( entryFilterMock.getXpath() ).andReturn( "Xpath" ).anyTimes();
        EasyMock.expect( entryFilterMock.getDomainEntryPointWrapper() ).andReturn( domainEntryPointWrapper ).anyTimes();
        EasyMock.expect( queryMock.setParameter( "xpath", "Xpath" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "depw", domainEntryPointWrapper ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.uniqueResult() ).andReturn( new EntryFilter() );

        //persistifyFilter
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaId" ) ).andReturn( queryMock );
        EasyMock.expect( filterMetaDataMock.getFilterId() ).andReturn( "Filter Id" );
        EasyMock.expect( queryMock.setParameter( "filterId", "Filter Id" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.uniqueResult() ).andReturn( null );
        EasyMock.expect( sessionMock.save( EasyMock.isA( FilterMetaData.class ) ) ).andReturn( null );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock, criteriaMock, filterMetaDataMock, entryFilterMock );
        cachePersistence.replaceFilterPersistence( filterMetaDatas );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock, criteriaMock, filterMetaDataMock, entryFilterMock );
    }


    @Test( expected = FilterCacheException.class )
    @Suite( groups = "checkintest" )
    public void testPersistFilterSchema_ThrowsNullPointerException( )
    {
        FilterMetaDataInterface filterMetaData = new FilterMetaData();

        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        cachePersistence.persistFilterSchema( filterMetaData );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );

    }


    @Test( expected = FilterCacheException.class )
    @Suite( groups = "checkintest" )
    public void testPersistFilterSchema_ThrowsHibernateException( )
    {
        //Override Methods from base abstract class - AbstractTfsHibernatePersistenceManager
        cachePersistence = new HibernateOracleFilterCachePersistence()
        {
            @Override
            protected DomainEntryPointWrapper persistifyDomainEntryPoint( org.hibernate.Session session, DomainEntryPointWrapper domainEntryPoint )
            {
                throw new HibernateException( "Boom!" );
            }


            @Override
            protected void persistifyVhimVersions( org.hibernate.Session session, Set<VhimVersionWrapper> vhimVersions )
            {
            }
        };

        cachePersistence.setSessionFactory( sessionFactoryMock );

        FilterMetaDataInterface filterMetaData = new FilterMetaData();
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        cachePersistence.persistFilterSchema( filterMetaData );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );

    }


    @Test
    @Suite( groups = "checkintest" )
    public void testLoadFilterIntoMemoryCache( )
    {
        FilterMemoryCacheInterface filterMemoryCacheMock = EasyMock.createMock( FilterMemoryCacheInterface.class );
        FilterMetaData filterMetaDataMock = EasyMock.createMock( FilterMetaData.class );

        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );

        // buildFilterIdQuery
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaId" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "filterId", "Filter Id" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.uniqueResult() ).andReturn( filterMetaDataMock );
        filterMemoryCacheMock.loadFilterMetaDataIntoMemoryCache( "Filter Id", filterMetaDataMock );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock, filterMemoryCacheMock, filterMetaDataMock );
        cachePersistence.loadFilterIntoMemoryCache( "Filter Id", filterMemoryCacheMock );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock, filterMemoryCacheMock, filterMetaDataMock );
    }


    @Test( expected = FilterCacheException.class )
    @Suite( groups = "checkintest" )
    public void testLoadFilterIntoMemoryCache_FilterMemoryCacheIsNull( )
    {
        FilterMemoryCacheInterface filterMemoryCache = null;

        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        cachePersistence.loadFilterIntoMemoryCache( "Filter Id", filterMemoryCache );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void loadAllFilterSchemasIntoMemoryCache( )
    {
        ArrayList<String> filterIds = new ArrayList<String>();
        filterIds.add( "filterId10400" );

        FilterMemoryCacheInterface filterMemoryCacheMock = EasyMock.createMock( FilterMemoryCacheInterface.class );
        FilterMetaData filterMetaDataMock = EasyMock.createMock( FilterMetaData.class );
        List<FilterMetaDataInterface> filterMetaDatas = new ArrayList<FilterMetaDataInterface>();
        filterMetaDatas.add( filterMetaDataMock );

        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );
        //loadFiltersFromPersistence
        // buildFilterStatusQuery
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaIdsByStatus" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "status", "ACTIVE" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.list() ).andReturn( filterIds );

        //loadFilterFromPersistence
        //buildFilterIdQuery
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaId" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "filterId", "filterId10400" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.uniqueResult() ).andReturn( filterMetaDataMock );
        EasyMock.expect( filterMetaDataMock.getFilterId() ).andReturn( "filterId10400" );
        filterMemoryCacheMock.loadFilterMetaDataIntoMemoryCache( "filterId10400", filterMetaDataMock );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock, filterMemoryCacheMock, filterMetaDataMock );
        cachePersistence.loadAllFilterSchemasIntoMemoryCache( filterMemoryCacheMock );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock, filterMemoryCacheMock, filterMetaDataMock );
    }


    @Test
    @Suite( groups = "checkintest" )
    public void testRemoveFilterSchema( )
    {
        //Expectations
        EasyMock.expect( sessionFactoryMock.getCurrentSession() ).andReturn( sessionMock );

        //buildFilterIdQuery
        EasyMock.expect( sessionMock.getNamedQuery( "FilterSchemaId" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.setParameter( "filterId", "filterId10400" ) ).andReturn( queryMock );
        EasyMock.expect( queryMock.uniqueResult() ).andReturn( new FilterMetaData() );
        sessionMock.delete( EasyMock.isA( FilterMetaData.class ) );

        EasyMock.replay( sessionFactoryMock, sessionMock, queryMock );
        cachePersistence.removeFilterSchema( "filterId10400" );
        EasyMock.verify( sessionFactoryMock, sessionMock, queryMock );
    }
}
