/**
 * ScheduleTimetableAction.java
 * Created Jun 9, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import static com.tandbergtv.watchpoint.pmm.entities.ContainerType.PARTNER;
import static com.tandbergtv.watchpoint.pmm.entities.TitleListType.PITCH;
import static com.tandbergtv.watchpoint.pmm.entities.TitleListType.PLANNER;
import static com.tandbergtv.watchpoint.pmm.web.schedule.ScheduleRequest.STARTDATE;
import static com.tandbergtv.watchpoint.pmm.web.schedule.ScheduleRequest.STARTDATE_PARAMETER;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.MappingDispatchAction;

import com.tandbergtv.watchpoint.pmm.entities.IContainer;
import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.schedule.ScheduleRuntimeException;
import com.tandbergtv.watchpoint.pmm.schedule.search.IScheduleSearchService;
import com.tandbergtv.watchpoint.pmm.web.util.CommonUtils;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.core.service.cache.ICacheService;
import com.tandbergtv.workflow.util.SearchCriteria;

/**
 * Controller class for displaying the schedule calendar view
 * 
 * @author Sahil Verma
 */
public class ScheduleTimetableAction extends MappingDispatchAction {

	private IScheduleSearchService service;
	
	private static final Logger logger = Logger.getLogger(ScheduleTimetableAction.class);
	
	/**
	 * Creates a ScheduleTimetableAction
	 */
	public ScheduleTimetableAction() {
		this.service = ServiceRegistry.getDefault().lookup(IScheduleSearchService.class);
	}
	
	/**
	 * Gets the schedules to be painted in the calendar
	 */
	public ActionForward getSchedules(ActionMapping mapping, ActionForm actionform,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		ScheduleTimetableForm form = (ScheduleTimetableForm)actionform;
		Date date = getStartDate(form);
		
		form.setCurrent(date);
		form.setQuery(getQueryString(request));
		
		logger.debug("Current month " + form.getCurrent());
		
		ScheduleCriteriaBuilder builder = ScheduleCriteriaBuilder.newInstance(request, form);
		
		SearchCriteria criteria = builder.getSearchCriteria();
		
		Collection<Schedule> schedules = service.search(criteria);
		
		for (Schedule schedule : schedules) {
			PartnerBean partner = getPartner(schedule);
			
			form.addSchedule(schedule, partner);
		}
		
		return mapping.findForward("default");
	}
	
	/**
	 * Returns the start date
	 * 
	 * @param form
	 * @return
	 * @throws ParseException 
	 */
	private Date getCurrentMonth(ScheduleTimetableForm form) throws ParseException {
		String s = form.getStartDate();
		
		if (s == null || s.length() == 0)
			return new Date();
		
		logger.debug("Start " + s);
		String format = CommonUtils.getApplicationUIResourceBundle().getString(CommonUtils.DATE_FORMAT);
		
		return new SimpleDateFormat(format).parse(s);
	}
	
	/**
	 * Returns the partner for the specified schedule
	 * 
	 * @param schedule
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private PartnerBean getPartner(Schedule schedule) {
		ICacheService<IContainer> cache =
			(ICacheService<IContainer>)ServiceRegistry.getDefault().lookup("Container Cache");
		PartnerBean partner = null;
		
		if (schedule.getType() == PITCH) {
			IContainer container = cache.get(schedule.getContextID().longValue());
			partner = new PartnerBean(container.getContainerId(), container.getContainerName(), schedule.getContextID());
		} else if (schedule.getType() == PLANNER) {
			Long partnerId = schedule.getSourcePartnerID();
			
			for (Serializable key : cache.getKeys()) {
				IContainer c = cache.get(key);
				
				if (c.getContainerId() == partnerId.longValue() && c.getContainerType() == PARTNER) {
					partner = new PartnerBean(c.getContainerId(), c.getContainerName(), (Long)key);
					break;
				}
			}
		} else {
			throw new ScheduleRuntimeException("Unknown schedule type: " + schedule.getType());
		}
		
		return partner;
	}
	
	private String getQueryString(HttpServletRequest request) {
		/* There just has to be a better way... */
		String query = request.getQueryString();
		
		if (query == null)
			query = "";
		
		logger.debug("Query " + query);
		
		String startDate = request.getParameter(STARTDATE_PARAMETER.toString());
		
		if (startDate != null)
			query = query.replace(STARTDATE.toString() + startDate, "");
		
		query = query.replace(STARTDATE_PARAMETER.toString() + "=" + startDate, "");

		// need to do this or else the back and forth links dont work in the calendar section.
		// remove '&month=[value]' from query string 
		String month = request.getParameter(ScheduleRequest.MONTH_PARAMETER.toString());
		month = month == null ? "" : month;
		query = query.replace(ScheduleRequest.MONTH.toString() + month, "");
		
		// remove '&year=[value]' from query string		
		String year = request.getParameter(ScheduleRequest.YEAR_PARAMETER.toString());
		year = year == null ? "" : year;
		query = query.replace(ScheduleRequest.YEAR.toString() + year, "");		
				
		return request.getRequestURI() + "?" + query;
	}
	
	/**
	 * If month and year are provided, use the first day of that month/year as
	 * the start date else use the current date.
	 * 
	 * @param form
	 * @return
	 */
	private Date getStartDate(ScheduleTimetableForm form) throws ParseException {
		String month = form.getMonth();
		String year = form.getYear(); 
		// Either the month or year could be selected to search.
		if ((month != null && month.trim().length() > 0)
				|| ( year != null && year.trim().length() > 0)) {
			// if only the year was specified, use the current month.
			if (month == null || month.trim().length() == 0) {
				Calendar cMonth = Calendar.getInstance();
				cMonth.setTime(new Date());
				month = String.valueOf(cMonth.get(Calendar.MONTH) + 1);
			}
			// if only the month was specified, use the current year.
			if (year == null || year.trim().length() == 0) {
				Calendar cYear = Calendar.getInstance();
				cYear.setTime(new Date());
				year = String.valueOf(cYear.get(Calendar.YEAR));
			}

			Calendar c = Calendar.getInstance();
			c.set(Calendar.DATE, 1);
			c.set(Calendar.MONTH, Integer.parseInt(month) - 1);
			c.set(Calendar.YEAR, Integer.parseInt(year));
			// reset time
			c.set(Calendar.HOUR, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			c.set(Calendar.MILLISECOND, 0);
			c.set(Calendar.AM_PM, Calendar.AM);
			
			return c.getTime();
		} else {			
			return getCurrentMonth(form);
		}		
	}
}
