/**
 * 
 */


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


import gov.va.med.cds.exception.ErrorCodeEnum;
import gov.va.med.cds.filter.EntryFilterInterface;
import gov.va.med.cds.filter.ParameterMapInterface;
import gov.va.med.cds.filter.QueryParameter;
import gov.va.med.cds.persistence.PersistenceException;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;


/**
 * @author DNS   egberb
 *
 */
public class TypedFilterParameterExtractor
    implements
        FilterParameterExtractorInterface
{

    /*
     * (non-Javadoc)
     * @see gov.va.med.cds.persistence.hibernate.FilterParameterExtractorInterface#extractNamedParameters(java.util.Map, gov.va.med.cds.filter.EntryFilterInterface)
     */
    @Override
    public Map<String, Object> extractNamedParameters( Map<String, QueryParameterTransformerInterface> parameterTransformerMap,
                    EntryFilterInterface entryFilter )
    {
        Map<String, Object> params = new HashMap<String, Object>();
        
        if ( entryFilter.hasRecordIdentifiers() ) // record identifiers query
        {
            QueryParameterTransformerInterface parameterTransformer = parameterTransformerMap.get( PN_RECORD_IDENTIFIERS );
            if(parameterTransformer != null)
            {
                parameterTransformer.transformAndSetParameter( PN_RECORD_IDENTIFIERS, entryFilter.getRecordIdentifiers(), params );
            }
            else
            {
                params.put( PN_RECORD_IDENTIFIERS, entryFilter.getRecordIdentifiers() );
            }
        }
        else if ( entryFilter.useDates() ) // person ids and date query.
        {
            // dates require a parameter transformer to facilitate querying. transformer must be present
            QueryParameterTransformerInterface startParamTransformer = parameterTransformerMap.get(PN_START_DATE);
            if( startParamTransformer != null )
            {
                startParamTransformer.transformAndSetParameter( PN_START_DATE, entryFilter.getStartDate(), params );
            }
            else
            {
                throw new PersistenceException( ErrorCodeEnum.PARAMETER_TRANSFORMER_EXPECTED_ERROR, PN_START_DATE );
            }
            
            QueryParameterTransformerInterface endParamTransformer = parameterTransformerMap.get(PN_END_DATE);
            if( endParamTransformer != null )
            {
                endParamTransformer.transformAndSetParameter( PN_END_DATE, entryFilter.getEndDate(), params );
            }
            else
            {
                throw new PersistenceException( ErrorCodeEnum.PARAMETER_TRANSFORMER_EXPECTED_ERROR, PN_END_DATE );
            }
        }
        
        ParameterMapInterface parameterMap = entryFilter.getAdditionalParametersMap();
        if ( parameterMap != null )
        {
            QueryParameterTransformerInterface dateTransformer = parameterTransformerMap.get( PN_DATE ); // used for transforming dates. 
            
            for ( String filterParameterName : parameterMap.getFilterParameterNames() )
            {
                QueryParameter<?> queryParameter = parameterMap.getParameterValue( filterParameterName );
                if ( queryParameter == null )
                {
                    throw new PersistenceException( ErrorCodeEnum.INVALID_OR_UNEXPECTED_QUERY_PARAM, filterParameterName );
                }
                
                if("dateRange".equals(queryParameter.getType()))
                {
                    Map<String, Object> dateRangesMap = (Map<String, Object>)params.get("dateRanges");
                    if(dateRangesMap == null)
                    {
                        dateRangesMap = new HashMap<String, Object>();
                        params.put( "dateRanges", dateRangesMap );
                    }
                    
                    Map<String, Calendar> dateRange = (Map<String, Calendar>)queryParameter.getValue();
                    Map<String, Object> paramsMap = new HashMap<String, Object>();
                    paramsMap.put("begin", dateTransformer.transform( dateRange.get("begin") ) );
                    paramsMap.put("end", dateTransformer.transform( dateRange.get("end") ) );
                    dateRangesMap.put(queryParameter.getName(), paramsMap);
                }
                else 
                {
                    params.put( queryParameter.getName(), queryParameter.getValue() );
                }
            }
        }
        
        if ( entryFilter.containsXpathFilterExpression() )
        {
            params.put( PN_XPATH_FILTER_EXPRESSION, entryFilter.getXpathFilterExpression() );
            params.put( PN_XPATH_FILTER_EXPRESSION_NAMESPACE, entryFilter.getXpathFilterExpressionNamespace());
        }

        return params;
    }

}
