/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.fw.batchprocess;

import java.util.List;

import org.apache.commons.lang.Validate;

import gov.va.med.fw.persistent.DAOOperations;

/**
 * Abstract base class for batch processing of bulk data where the input source
 * is a database query.
 * 
 * Created Feb 1, 2006 2:41:40 PM
 * 
 * @author DNS   BOHMEG
 */
public abstract class AbstractDataQueryProcess extends AbstractDataProcess {
    private DataQueryDetail queryDetail = new DataQueryDetail();

	private DAOOperations dao;

	
    protected DataProcessExecutionContext createDataProcessExecutionContext() {
		DataQueryProcessExecutionContext context = new DataQueryProcessExecutionContext();
		context.setProcessStatistics(createProcessStatistics());
		return context;
	}
	
	protected ProcessStatistics createProcessStatistics() {
		return new DataQueryProcessStatistics();
	}
	
	// not marked final for framework overrides
	protected List acquireData(DataProcessExecutionContext context)
			throws Exception {
        DataQueryProcessExecutionContext queryContext = (DataQueryProcessExecutionContext) context;
        queryContext.setCurrentDataQuery(queryDetail);

		List acquiredData = doAcquireData(queryContext);
		// let this happen indirectly by implementation use of incrementNumberOf*Records
		//context.getProcessStatistics().setNumberOfTotalRecords(acquiredData.size());
		if(logger.isInfoEnabled() && acquiredData != null)
			logger.info("AbstractDataQueryProcess acquired " + acquiredData.size() + " data records");
		return acquiredData;
	}
        
	
	// not marked final for subclasses
	protected List doAcquireData(DataQueryProcessExecutionContext context) throws Exception {
		return executeQuery(context);
	}
    
    // subclasses can override
    protected List executeQuery(DataQueryProcessExecutionContext context) throws Exception {
        DataQueryDetail currentQuery = context.getCurrentDataQuery();
        return getDao().findByNamedQueryAndNamedParam(currentQuery.getQuery().getQuery(), currentQuery.getQuery().getParamNames(),
        		currentQuery.getQuery().getParamValues());            
    }    

	/**
	 * @return Returns the dao.
	 */
	public DAOOperations getDao() {
		return dao;
	}

	/**
	 * @param dao
	 *            The dao to set.
	 */
	public void setDao(DAOOperations dao) {
		this.dao = dao;
	}

	/**
	 * @return Returns the queryName.
	 */
	public String getQueryName() {
		return queryDetail.getQuery().getQuery();
	}

	/**
	 * @param queryName
	 *            The queryName to set.
	 */
	public void setQueryName(String queryName) {
        queryDetail.getQuery().setQuery(queryName);
	}

	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		Validate.notNull(dao, "A dao is needed to acquire data");		
		validateQuery();
	}
	
	// not marked final for framework overrides
	protected void validateQuery() {
        Validate.notNull(queryDetail, "A DataQueryDetail is needed to acquire data");
		Validate.notNull(queryDetail.getQuery().getQuery(), "A query name is needed to acquire data");
	}

    
    /**
     * @return Returns the paramNames.
     */
    public String[] getParamNames() {
        return queryDetail.getQuery().getParamNames();
    }

    
    /**
     * @param paramNames The paramNames to set.
     */
    public void setParamNames(String[] paramNames) {
        queryDetail.getQuery().setParamNames(paramNames);
    }

    
    /**
     * @return Returns the paramValues.
     */
    public Object[] getParamValues() {
        return queryDetail.getQuery().getParamValues();
    }

    
    /**
     * @param paramValues The paramValues to set.
     */
    public void setParamValues(Object[] paramValues) {
        queryDetail.getQuery().setParamValues(paramValues);
    }

    
    /**
     * @return Returns the queryDetail.
     */
    public DataQueryDetail getQueryDetail() {
        return queryDetail;
    }

    
    /**
     * @param queryDetail The queryDetail to set.
     */
    public void setQueryDetail(DataQueryDetail queryDetail) {
        this.queryDetail = queryDetail;
    }
}
