/**
 * TitleAssociatedHandler.java
 * Created on Jun 5, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.job.handler;

import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.JOB_RULE_NAME;
import static com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants.JOB_RULE_PARAMETERS;
import static com.tandbergtv.workflow.driver.search.SearchOperator.EQUAL;
import static com.tandbergtv.workflow.driver.search.SearchType.STRING;
import static java.lang.Integer.MAX_VALUE;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.tandbergtv.metadatamanager.search.AssetSearchKey;
import com.tandbergtv.watchpoint.pmm.entities.RuleParameter;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.job.callback.IJobCallback;
import com.tandbergtv.watchpoint.pmm.job.referenceEvaluator.ParameterReferencePath;
import com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants;
import com.tandbergtv.watchpoint.pmm.title.search.ITitleSearchService;
import com.tandbergtv.watchpoint.pmm.title.search.ParamType;
import com.tandbergtv.watchpoint.pmm.title.search.SearchField;
import com.tandbergtv.watchpoint.pmm.title.search.TitleSearchCriteriaBuilder;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.util.SearchCriteria;

/**
 * This class is responsible for getting all titles that match the given criteria (e.g. 3 days
 * before license start date, 3 days after license end date) and starting a work order for each of
 * them with the required info passed along in the callbackinfo
 * 
 * @author spuranik
 */

public class TitleAssociatedHandler extends AbstractTitleAssociatedHandler {

	// This is how values (which are dates) are stored in the metadata table in the db.
	private static String DATE_FORMAT = "yyyy-MM-dd";
	private Logger logger = Logger.getLogger(TitleAssociatedHandler.class);

	/**
	 * @param next
	 */
	public TitleAssociatedHandler(IJobCallback next) {
		super(next);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.handler.AbstractTitleAssociatedHandler#buildSearchCriteria(com.tandbergtv.watchpoint.pmm.job.referenceEvaluator.ParameterReferencePath,
	 *      java.lang.Object)
	 */
	@SuppressWarnings("unchecked")
	private SearchCriteria buildSearchCriteria(ParameterReferencePath path, Map<String, Object> searchInfo, 
		Date jobExecutionDate) {
		// compute the date which will be used in the search criteria
		String ruleName = (String) searchInfo.get(JOB_RULE_NAME);
		List<RuleParameter> ruleParameters = (List<RuleParameter>) searchInfo.get(JOB_RULE_PARAMETERS);
		
		Date date = getSearchDate(ruleName, ruleParameters, jobExecutionDate);

		SearchField field = getSearchFields(path, date);
		
		/* Look at all the fields of the root asset, the search field already contains the asset type */
		String property = AssetSearchKey.ALL_DESCENDANT_FIELDS.toString();
		
		SearchCriteria criteria = 
			TitleSearchCriteriaBuilder.getCriteria(true, null, property, field, 0, MAX_VALUE, 
				null, null, null);

		return criteria;
	}
	
	@SuppressWarnings("serial")
	private SearchField getSearchFields(ParameterReferencePath path, final Date date) {
		SearchField field = new SearchField();
		
		field.setName(path.getPropertyField());
		field.setParamType(ParamType.VALUE);
		field.setSearchOperator(EQUAL);
		field.setSearchType(STRING);
		
		field.setSectionName(path.getName());
		
		field.setValues(new ArrayList<String>() {{ add(formatSearchDate(date)); }});

		return field;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.handler.AbstractTitleAssociatedHandler#searchTitles(com.tandbergtv.workflow.util.SearchCriteria)
	 */
	@Override
	protected Collection<?> search(ParameterReferencePath path, Map<String, Object> searchInfo, Date date) {
		SearchCriteria criteria = buildSearchCriteria(path, searchInfo, date);
		ITitleSearchService searchService = ServiceRegistry.getDefault().lookup(ITitleSearchService.class);
		Collection<Title> titles = searchService.search(criteria);
		
		logger.info("Search resulted in " + titles.size() + " titles.");
		
		return titles;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.handler.AbstractTitleAssociatedHandler#createWorkOrder(java.util.Collection,
	 *      java.util.Map)
	 */
	@Override
	@SuppressWarnings("unchecked")
	protected void processItems(Collection<?> items, Map<String, Object> callbackInfo) {
		callbackInfo.put(JobScheduleInfoConstants.TITLES, (Collection<Title>) items);
		
		this.next.executeJob(callbackInfo, null);
	}

	/**
	 * formats the given date in the form yyyy-MM-dd.
	 * 
	 * @param searchDate
	 * @return
	 */
	private String formatSearchDate(Date searchDate) {
		SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
		df.setLenient(false);
		return df.format(searchDate);
	}
}
