/**
 * ScheduleCriteriaBuilder.java
 * Created Aug 14, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import static com.tandbergtv.watchpoint.pmm.schedule.search.ScheduleSearchKey.PITCH_DATE;
import static com.tandbergtv.watchpoint.pmm.schedule.search.ScheduleSearchKey.TITLE_LIST_TYPE;
import static com.tandbergtv.workflow.driver.search.SearchParameterBase.DATE_FORMAT;
import static com.tandbergtv.workflow.driver.search.SearchType.DATE;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;

import com.tandbergtv.watchpoint.pmm.entities.ScheduleProxy;
import com.tandbergtv.watchpoint.pmm.entities.TitleListType;
import com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder;
import com.tandbergtv.watchpoint.pmm.web.util.PMMPageconfigHelper;
import com.tandbergtv.watchpoint.search.Entity;
import com.tandbergtv.workflow.driver.search.ListParameter;
import com.tandbergtv.workflow.driver.search.RangeParameter;
import com.tandbergtv.workflow.driver.search.SearchType;
import com.tandbergtv.workflow.driver.search.ValueParameter;
import com.tandbergtv.workflow.util.SearchCriteria;
import com.tandbergtv.workflow.web.page.Field;
import com.tandbergtv.workflow.web.page.Page;
import com.tandbergtv.workflow.web.page.PageConfig;

/**
 * Builds a search criteria for the schedule search page. Note that the criteria are built for 
 * the ScheduleProxy type, instead of the heavyweight Schedule.
 * 
 * @author Sahil Verma
 */
public class ScheduleCriteriaBuilder extends AbstractSearchCriteriaBuilder {

	private HttpServletRequest request;
	
	private ActionForm form;
	
	private static final Logger logger = Logger.getLogger(ScheduleCriteriaBuilder.class);
	
	private ScheduleCriteriaBuilder(HttpServletRequest request, ActionForm form) {
		this.request = request;
		this.form = form;
	}
	
	/**
	 * Returns a new search criteria builder
	 * 
	 * @param request
	 * @param form
	 * @return
	 */
	public static ScheduleCriteriaBuilder newInstance(HttpServletRequest request, ActionForm form) {
		return new ScheduleCriteriaBuilder(request, form);
	}
	
	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getSearchCriteria()
	 */
	public SearchCriteria getSearchCriteria() {
		SearchCriteria criteria = super.getSearchCriteria();
		ScheduleTimetableForm form = ScheduleTimetableForm.class.cast(getForm());
		
		/* Add the time window */
		Date start = form.getCurrent();
		Date end = getMonthEnd(start);
		
		logger.debug("Start " + start + " end " + end);
		
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
		RangeParameter range = new RangeParameter(PITCH_DATE.toString(), DATE, formatter.format(start));
		
		range.setTo(formatter.format(end));
		
		Entity e = getEntity(criteria);
		
		e.addParameter(range);
		
		return criteria;
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getDefaultSearchCriteria()
	 */
	protected SearchCriteria getDefaultSearchCriteria() {
		SearchCriteria criteria = new SearchCriteria();
		
		Entity schedule = new Entity("schedule", ScheduleProxy.class, "s");

		schedule.addParameter(new ValueParameter("isActive", SearchType.NUMERIC, 1));
		
		ListParameter types = new ListParameter(TITLE_LIST_TYPE.toString(), SearchType.NUMERIC);
		
		types.addValues(TitleListType.PLANNER.ordinal(), TitleListType.PITCH.ordinal());
		
		schedule.addParameter(types);
		
		criteria.addParameter(schedule);
		
		return criteria;
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getEntity(com.tandbergtv.workflow.util.SearchCriteria)
	 */
	protected Entity getEntity(SearchCriteria criteria) {
		return criteria.getParameter("schedule", Entity.class);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getPage()
	 */
	protected Page getPage() {
		Page page = null;
		
		try {
			page = PageConfig.getInstance().getPage("schedulesearch",
					PMMPageconfigHelper.getPageConfigFile());
		} catch (Exception e) {
			throw new RuntimeException("Failed to build search page", e);
		}
		
		return page;
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getForm()
	 */
	protected ActionForm getForm() {
		return this.form;
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.search.AbstractSearchCriteriaBuilder#getRequest()
	 */
	protected HttpServletRequest getRequest() {
		return this.request;
	}
	
	/**
	 * Gets the last day of the current month
	 * 
	 * @return
	 */
	private Date getMonthEnd(Date date) {
		Calendar calendar = new GregorianCalendar();
		
		calendar.setTime(date);
		int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		
		/*
		 * HACK! The end date gets added to a range, which ultimately ends up getting incremented
		 * by one day. Don't ask me, it's some open or closed interval shite.
		 */
		calendar.set(Calendar.DAY_OF_MONTH, max - 1);
		
		return calendar.getTime();
	}	

	protected void addSearchCriteria(SearchCriteria criteria, Field field,
			String... values) {
		if (!skipField(field.getName())) {
			super.addSearchCriteria(criteria, field, values);
		}
	}

	/**
	 * Returns true if the field name is found in the list of fields that should
	 * not be included in the search criteria.
	 * 
	 * @param name
	 * 	name of field to search in the list of fields excluded during search
	 * @return
	 * 	true/false based on whether the name was found in the list or not. 
	 */
	private boolean skipField(String name) {
		// currently month and year fields are excluded from the search
		return (name.equals(ScheduleRequest.MONTH_PARAMETER.toString()) || name
				.equals(ScheduleRequest.YEAR_PARAMETER.toString()));		
	}
}
