/**
 * TitleAssociatedHandler.java
 * Created on Jun 5, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.job.handler;

import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.tandbergtv.watchpoint.pmm.entities.IContainer;
import com.tandbergtv.watchpoint.pmm.entities.JobParameter;
import com.tandbergtv.watchpoint.pmm.entities.RuleParameter;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.job.callback.CallbackHelper;
import com.tandbergtv.watchpoint.pmm.job.referenceEvaluator.ParameterReferencePath;
import com.tandbergtv.watchpoint.pmm.job.referenceEvaluator.ReferenceEvaluatorChain;
import com.tandbergtv.watchpoint.pmm.job.util.JobScheduleInfoConstants;
import com.tandbergtv.watchpoint.pmm.title.search.ITitleSearchService;
import com.tandbergtv.watchpoint.pmm.title.search.TitleSearchKey;
import com.tandbergtv.watchpoint.search.Entity;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.driver.search.SearchOperator;
import com.tandbergtv.workflow.driver.search.SearchType;
import com.tandbergtv.workflow.driver.search.ValueParameter;
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);

	/*
	 * (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) {
		try {
			// compute the date which will be used in the search criteria
			String ruleName = (String) searchInfo.get(JobScheduleInfoConstants.JOB_RULE_NAME);
			List<RuleParameter> ruleParameters = (List<RuleParameter>) searchInfo
					.get(JobScheduleInfoConstants.JOB_RULE_PARAMETERS);
			Date searchDate = getSearchDate(ruleName, ruleParameters, jobExecutionDate);

			SearchCriteria criteria = new SearchCriteria();

			// title whose name = name in the path (parameter reference)
			Entity title = new Entity("title", Title.class, "t");
			title.addParameter(new ValueParameter("name", SearchType.STRING, path.getName()));
			title.addParameter(new ValueParameter("isActive", SearchType.NUMERIC, 1));
			criteria.addParameter(title);

			// metadata with the specified name and value as per the path (parameter reference)
			Entity metadata = new Entity("metadata", TitleSearchKey.METADATA.toString(), "m");
			
			metadata.addParameter(new ValueParameter("name", SearchType.STRING, path
					.getPropertyField()));
			metadata.addParameter(new ValueParameter("value", SearchType.STRING, false,
					formatSearchDate(searchDate), SearchOperator.LIKE));
			title.addParameter(metadata);

			return criteria;
		} catch (RuntimeException e) {
			/*
			 * Why? What can go wrong? Even if in the unlikely event that something fails, the 
			 * caller is already handling the exception... 
			 */
			logger.error("Error while building search criteria for job: "
					+ searchInfo.get(JobScheduleInfoConstants.JOB_NAME), e);
		}
		return null;
	}

	/*
	 * (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 jobExecutionDate) {
		SearchCriteria criteria = buildSearchCriteria(path, searchInfo, jobExecutionDate);

		if (criteria != null) {
			try {
				ITitleSearchService searchService = ServiceRegistry.getDefault().lookup(
						ITitleSearchService.class);
				Collection<Title> titles = searchService.search(criteria);
				logger.debug("Search resulted in " + titles.size() + " titles.");
				return titles;
			} catch (RuntimeException e) {
				IContainer container = CallbackHelper.getContainer(searchInfo);
				String errorMsg = "Job execution failed for job: "
						+ searchInfo.get(JobScheduleInfoConstants.JOB_NAME) + " ["
						+ container.getContainerType() + ":" + container.getContainerName() + "]"
						+ " Error while searching for titles.";
				logger.error(errorMsg, e);
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.watchpoint.pmm.job.handler.AbstractTitleAssociatedHandler#createWorkOrder(java.util.Collection,
	 *      java.util.Map)
	 */
	@Override
	@SuppressWarnings("unchecked")
	@Deprecated
	protected void processItems(Collection<?> items, Map<String, Object> callbackInfo) {
		/*String templateName = (String) callbackInfo
				.get(JobScheduleInfoConstants.JOB_SELECTED_TEMPLATE_NAME);
		String priority = (String) callbackInfo.get(JobScheduleInfoConstants.JOB_PRIORITY);

		ReferenceEvaluatorChain evaluatorChain = ReferenceEvaluatorChain.getInstance();

		Collection<Title> titles = (Collection<Title>) items;
		for (Title title : titles) {
			try {
				Title rootTitle = title.getRoot();
				// need to clone this or else the evaluator will substitute values
				// only for the first title.
				Map<String, Object> clone = CallbackHelper.clone(callbackInfo);

				// evaluate parameter references for the root title for this title.
				evaluatorChain.evaluate(rootTitle, clone);

				// create a WO now using these parameters
				logger.debug("Create WO for title: " + rootTitle.getId());
				CallbackHelper.createWorkOrder(templateName, priority, (List<JobParameter>) clone
						.get(JobScheduleInfoConstants.JOB_PARAMETERS));
				logger.debug("Done creating WO for title: " + rootTitle.getId());
			} catch (RuntimeException e) {
				IContainer container = CallbackHelper.getContainer(callbackInfo);
				logger.error("Job execution failed for: "
						+ callbackInfo.get(JobScheduleInfoConstants.JOB_NAME) + " ["
						+ container.getContainerType() + ":" + container.getContainerName() + "]"
						+ " Error while evaluating parameters or executing job: " + " for title: "
						+ title.getRoot().getId(), e);
			}
		}*/
	}

	/**
	 * 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);
	}
}
