/**
 * GetScheduleIdMessageHandler.java
 * Created on Sep 19, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.communication.handlers;

import static com.tandbergtv.watchpoint.pmm.schedule.search.ScheduleSearchKey.ACTIVE;
import static com.tandbergtv.watchpoint.pmm.schedule.search.ScheduleSearchKey.CONTEXT;
import static com.tandbergtv.watchpoint.pmm.schedule.search.ScheduleSearchKey.PITCH_DATE;
import static com.tandbergtv.workflow.driver.search.SearchType.DATE;
import static com.tandbergtv.workflow.driver.search.SearchType.NUMERIC;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

import org.apache.log4j.Logger;

import com.tandbergtv.watchpoint.communication.Util;
import com.tandbergtv.watchpoint.pmm.communication.HandlerErrorCode;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandler;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandlerException;
import com.tandbergtv.watchpoint.pmm.entities.ContainerType;
import com.tandbergtv.watchpoint.pmm.entities.DistributionSchedule;
import com.tandbergtv.watchpoint.pmm.entities.IContainer;
import com.tandbergtv.watchpoint.pmm.entities.Partner;
import com.tandbergtv.watchpoint.pmm.entities.PartnerType;
import com.tandbergtv.watchpoint.pmm.entities.Planner;
import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.schedule.search.IScheduleSearchService;
import com.tandbergtv.watchpoint.search.Entity;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.core.service.cache.ICacheService;
import com.tandbergtv.workflow.driver.search.RangeParameter;
import com.tandbergtv.workflow.driver.search.SearchParameterBase;
import com.tandbergtv.workflow.driver.search.SortParameter;
import com.tandbergtv.workflow.driver.search.ValueParameter;
import com.tandbergtv.workflow.message.WorkflowMessage;
import com.tandbergtv.workflow.message.WorkflowMessage.MessageType;
import com.tandbergtv.workflow.util.SearchCriteria;
import com.tandbergtv.workflow.util.SortingOrder;

/**
 * @author Vlada Jakobac
 *
 */
public class GetScheduleIdMessageHandler implements MessageHandler {

	private static final String IS_PLANNER = "isPlanner";
	private static final String TITLE_ID = "titleId";
	private static final String SCHEDULE_ID = "scheduleId";
	private static final String CONTEXT_ID = "contextId";
	private static String CONTAINER_CACHE_SERVICE_NAME = "Container Cache";
	private static final Logger logger = Logger.getLogger(GetScheduleIdMessageHandler.class);
	
	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.communication.MessageHandler#handleMessage(com.tandbergtv.workflow.message.WorkflowMessage)
	 */
	public WorkflowMessage handleMessage(WorkflowMessage message)
			throws Exception {
		Util.validateRequired(message, CONTEXT_ID, TITLE_ID, IS_PLANNER);

		boolean isPlanner = Util.getBooleanValue(message, IS_PLANNER);
		long titleId = Util.getLongValue(message, TITLE_ID);
		long contextId = Util.getLongValue(message, CONTEXT_ID);
		
		if(titleId < 1)
			throw new IllegalArgumentException(TITLE_ID + " has to be greater than zero");
		if(contextId < 1)
			throw new IllegalArgumentException(CONTEXT_ID + " has to be greater than zero");		
		
		SearchCriteria criteria = new SearchCriteria();
		Entity e; 
		
		if (isPlanner){
			e = new Entity("planner", Planner.class, "p");
			long partnerId = determinePartnerId(contextId);
			e.addParameter(new ValueParameter("sourcePartnerID", NUMERIC,
					partnerId));
			e.addParameter(getFutureDateRangeCriterion());
			e.addParameter(new SortParameter(PITCH_DATE.toString(), SortingOrder.ASCENDING));
		} else {//pitch schedule
			e = new Entity("pitch", DistributionSchedule.class, "d");
			e.addParameter(new ValueParameter(CONTEXT.toString(), NUMERIC,
					contextId));
			e.addParameter(getPastDateRangeCriterion());
			e.addParameter(new SortParameter(PITCH_DATE.toString(), SortingOrder.DESCENDING));
		}
		
		e.addParameter(new ValueParameter(ACTIVE.toString(), NUMERIC, 1));		
		criteria.addParameter(e);
		
		IScheduleSearchService service = ServiceRegistry.getDefault().lookup(IScheduleSearchService.class);
		Collection<Schedule> schedules = service.search(criteria);
		logger.debug("Found " + schedules.size() + " schedules.");
		String scheduleId = "";
		for (Schedule schedule : schedules) {
			Collection<Title> titles = schedule.getTitles();
			for (Title title : titles){
				if (title.getId() == titleId){
					scheduleId = Long.toString(schedule.getId());
					logger.debug("Found scheduleId=" + scheduleId);
					break;
				}				
			}
			if (!scheduleId.equals(""))
				break;
		}
		
		WorkflowMessage response = new WorkflowMessage(message.getMessageUID(), message.getKey(),
				MessageType.ack);
		response.putValue(SCHEDULE_ID, scheduleId);
		
		return response;
	}

	@SuppressWarnings("unchecked")
	private long determinePartnerId(long contextId) throws MessageHandlerException {
		Partner result = null;
		ICacheService<IContainer> containerCache = (ICacheService<IContainer>) ServiceRegistry
				.getDefault().lookup(CONTAINER_CACHE_SERVICE_NAME);
		IContainer container = containerCache.get(contextId);
		if (container != null && container.getContainerType() == ContainerType.PARTNER) {
			Partner partner = (Partner) container;
			if (partner.getType() == PartnerType.SOURCE) {
				result = partner;
				logger.debug("Found sourcePartnerId=" + result.getId());
				return result.getId();
			}
		}
		throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, "Failed to find a valid source partner for context id: " + contextId);
	}

	private SearchParameterBase getPastDateRangeCriterion() {
		/* Search for schedules within the past time window */
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		RangeParameter range = new RangeParameter(PITCH_DATE.toString(), DATE);		
		range.setTo(formatter.format(new Date()));
		
		return range;
	}
	
	private SearchParameterBase getFutureDateRangeCriterion() {
		/* Search for schedules within the future time window */
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		RangeParameter range = new RangeParameter(PITCH_DATE.toString(), DATE, formatter.format(new Date()));
		
		return range;
	}
}
