/**
 * 
 */


package gov.va.med.cds.persistence;


import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.persistence.hibernate.DefaultQueryWork;
import gov.va.med.cds.persistence.hibernate.FilterParameterExtractorInterface;
import gov.va.med.cds.persistence.hibernate.LegacyFilterParameterExtractor;
import gov.va.med.cds.persistence.hibernate.LegacyQueryNameBuilder;
import gov.va.med.cds.persistence.hibernate.ModelAssemblerInterface;
import gov.va.med.cds.persistence.hibernate.QueryNameBuilderInterface;
import gov.va.med.cds.persistence.hibernate.QueryParameterBinderInterface;
import gov.va.med.cds.persistence.hibernate.QueryParameterTransformerInterface;
import gov.va.med.cds.template.generated.JaxBMarshallerUnmarshallerInterface;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;


/**
 * @author DNS   egberb
 *
 */
public class DefaultAssociationBasedQueryStrategy
    implements
        QueryStrategyInterface,
        BeanFactoryAware
{

    private ModelAssemblerInterface modelAssembler;

    protected Map<String, QueryAssociationInterface> templateAssociationMap;

    protected String applicationName;

    protected Map<String, String> templateTimeoutMap;

    protected String interceptorBeanName;

    protected BeanFactory beanFactory;
    
    protected QueryNameBuilderInterface queryNameBuilder = new LegacyQueryNameBuilder();
    
    protected FilterParameterExtractorInterface filterParameterExtractor = new LegacyFilterParameterExtractor();
    
    protected Map<String, QueryParameterTransformerInterface> parameterTransformerMap = null;
    
    protected QueryParameterBinderInterface queryParameterBinder = null;


    @Override
    public void setBeanFactory( BeanFactory beanFactory )
        throws BeansException
    {
        this.beanFactory = beanFactory;
    }


    /*
     * (non-Javadoc)
     * @see gov.va.med.cds.persistence.QueryStrategyInterface#createQueryWork(org.hibernate.SessionFactory, gov.va.med.cds.filter.EntryFilterInterface, java.util.List, java.lang.Class)
     */
    @Override
    public List<QueryWorkInterface> createQueryWork( SessionFactory factory, EntryFilterInterface entryFilter, List<String> personIdentifiers,
                    Class<?> pointInTimeUserType, String siteId, JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller )
    
    {
        List<QueryWorkInterface> queryWork = new ArrayList<QueryWorkInterface>();

        for ( QueryAssociationInterface queryAssociation : templateAssociationMap.values() )
        {
            Session session = null;
            if ( this.interceptorBeanName != null && this.interceptorBeanName.length() > 0 )
            {
            	session = factory.withOptions().interceptor(this.beanFactory.getBean( interceptorBeanName, Interceptor.class )).openSession();
            }
            else
            {
                session = factory.openSession();
            }

            // create work for each of the query meta data(s) found in the query plan map
            QueryWorkInterface work = createQueryWork( session, queryAssociation, entryFilter, personIdentifiers, pointInTimeUserType, siteId, marshallerUnmarshaller );
            queryWork.add( work );
        }

        return queryWork;
    }


	protected QueryWorkInterface createQueryWork( Session session, QueryAssociationInterface queryAssociation, EntryFilterInterface entryFilter,
                    List<String> personIdentifiers, Class<?> pointInTimeUserType, String siteId, JaxBMarshallerUnmarshallerInterface marshallerUnmarshaller )
    {
        QueryWorkInterface queryWork = new DefaultQueryWork( session, queryAssociation, entryFilter, queryNameBuilder, filterParameterExtractor, 
                        parameterTransformerMap, queryParameterBinder, templateTimeoutMap, personIdentifiers, pointInTimeUserType, applicationName, siteId, marshallerUnmarshaller );
        return queryWork;
    }


    /* (non-Javadoc)
     * @see gov.va.med.cds.persistence.QueryStrategyInterface#getModelAssembler()
     */
    @Override
    public ModelAssemblerInterface getModelAssembler( )
    {
        return this.modelAssembler;
    }


    /**
     * 
     * @param queryPlanMap
     */
    public void setQueryPlanMap( Map<String, QueryAssociationInterface> queryPlanMap )
    {
        this.templateAssociationMap = queryPlanMap;
    }


    /**
     * 
     * @param modelAssembler
     */
    public void setModelAssembler( ModelAssemblerInterface modelAssembler )
    {
        this.modelAssembler = modelAssembler;
    }


    public void setTemplateTimeoutMap( Map<String, String> templateTimeoutMap )
    {
        this.templateTimeoutMap = templateTimeoutMap;
    }


    public void setApplicationName( String applicationName )
    {
        this.applicationName = applicationName;
    }


    public Map<String, String> getTemplateTimeoutMap( )
    {
        return templateTimeoutMap;
    }

    public void setInterceptorBeanName( String interceptorBeanName )
    {
        this.interceptorBeanName = interceptorBeanName;
    }
    
    public void setQueryNameBuilder( QueryNameBuilderInterface queryNameBuilder )
    {
        this.queryNameBuilder = queryNameBuilder;
    }
    
    public void setFilterParameterExtractor( FilterParameterExtractorInterface filterParameterExtractor )
    {
        this.filterParameterExtractor = filterParameterExtractor;
    }
    
    public void setParameterTransformerMap( Map<String, QueryParameterTransformerInterface> parameterTransformerMap )
    {
        this.parameterTransformerMap = parameterTransformerMap;
    }
    
    public void setQueryParameterBinder( QueryParameterBinderInterface queryParameterBinder )
    {
        this.queryParameterBinder = queryParameterBinder;
    }

}
