/**
 * ScheduleTimetableForm.java
 * Created Jun 9, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import static com.tandbergtv.watchpoint.pmm.web.schedule.ScheduleRequest.STARTDATE;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Logger;

import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.web.title.PagingForm;
import com.tandbergtv.watchpoint.pmm.web.util.CommonUtils;
import com.tandbergtv.watchpoint.pmm.web.util.PMMPageconfigHelper;
import com.tandbergtv.workflow.web.page.Page;
import com.tandbergtv.workflow.web.page.PageConfig;
import com.tandbergtv.workflow.web.table.Table;

/**
 * This form is used to paint the calendar view of planners and pitch schedules
 * 
 * @author Sahil Verma
 */
public class ScheduleTimetableForm extends PagingForm {

	private Map<String, ScheduleTimeline> timelines;
	
	private Date next;
	
	private Date previous;
	
	private Date current;
	
	private DateFormat monthDateFormatter;
	
	private DateFormat formatter;
	
	private String startDate;
	
	private String month;
	
	private String year;
	
	private static final String SEARCH_PAGE = "schedulesearch";
	
	private static final Logger logger = Logger.getLogger(ScheduleTimetableForm.class);
	
	private String spec;

	/**
	 * 
	 */
	private static final long serialVersionUID = 7492230738451570978L;

	/**
	 * Creates a ScheduleTimetableForm
	 */
	public ScheduleTimetableForm() {
		this.timelines = new TreeMap<String, ScheduleTimeline>();
		this.monthDateFormatter = new SimpleDateFormat("dd");
		String format = CommonUtils.getApplicationUIResourceBundle().getString(CommonUtils.DATE_FORMAT);
		this.formatter = new SimpleDateFormat(format);
	}

	/**
	 * @return the start
	 */
	public String getStartDate() {
		return this.startDate;
	}

	/**
	 * @param start the start to set
	 */
	public void setStartDate(String start) {
		this.startDate = start;
	}
	
	/**
	 * Returns the timelines, one for each source or destination
	 * 
	 * @return
	 */
	public Collection<ScheduleTimeline> getTimelines() {
		return this.timelines.values();
	}
	
	/**
	 * Determines if there are any schedules for this month
	 * 
	 * @return
	 */
	public boolean getHasSchedules() {
		return this.timelines.size() > 0;
	}
	
	/**
	 * Returns the first day of the next month
	 * 
	 * @return
	 */
	public Date getNext() {
		return this.next;
	}

	/**
	 * Returns the first day of the previous month
	 * 
	 * @return
	 */
	public Date getPrevious() {
		return this.previous;
	}

	/**
	 * Returns the first day of the current month
	 * 
	 * @return
	 */
	public Date getCurrent() {
		return this.current;
	}
	
	/**
	 * Sets the current month
	 * 
	 * @param current
	 */
	public void setCurrent(Date current) {
		Calendar calendar = new GregorianCalendar();
		
		calendar.setTime(current);
		calendar.set(Calendar.DATE, 1);
		
		/* Don't fucking ask */
		calendar.set(Calendar.HOUR, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		calendar.set(Calendar.AM_PM, Calendar.AM);
		
		this.current = calendar.getTime();
		this.previous = getMonth(this.current, -1);
		this.next = getMonth(this.current, 1);
	}
	
	/**
	 * Adds the specified schedule for the partner
	 * 
	 * @param schedule
	 * @param partner
	 */
	public void addSchedule(Schedule schedule, PartnerBean partner) {
		String key = partner.getName();
		ScheduleTimeline timeline = this.timelines.get(key);
		
		if (timeline == null) {
			timeline = new ScheduleTimeline(partner.getContextId(), key, this.current);
			this.timelines.put(key, timeline);
		}
		
		timeline.addSchedule(schedule);
		logger.debug("Added timeline " + timeline + ", total " + this.timelines.size());
	}
	
	/**
	 * Returns the days of the week for the current month
	 * @return
	 */
	public Collection<String> getDaysOfWeek() {
		Collection<String> daysOfWeek = new ArrayList<String>();
		Calendar calendar = new GregorianCalendar();
		
		calendar.setTime(this.current);
		int min = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
		int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		
		for (int i = min; i <= max; i++) {
			daysOfWeek.add(formatDayOfWeek(calendar.get(Calendar.DAY_OF_WEEK)));
			calendar.roll(Calendar.DAY_OF_MONTH, true);
		}
		
		return daysOfWeek;
	}
	
	/**
	 * Returns the appropriate abbreviation for the day of the week. 
	 * Since 3 letter week of the day is the minimum number of chars that
	 * java api supports, we have to do this ourselves.
	 * 
	 * @param dayOfWeek
	 * @return
	 */
	private String formatDayOfWeek(int dayOfWeek) {

		switch (dayOfWeek) {
		case Calendar.SUNDAY:
			return "Su";
		case Calendar.MONDAY:
			return "M";
		case Calendar.TUESDAY:
			return "T";
		case Calendar.WEDNESDAY:
			return "W";
		case Calendar.THURSDAY:
			return "Th";
		case Calendar.FRIDAY:
			return "F";
		case Calendar.SATURDAY:
			return "S";		
		}
		return "";
	}

	/**
	 * Returns the days of the current month
	 * 
	 * @return
	 */
	public Collection<String> getDays() {
		Collection<String> days = new ArrayList<String>();
		Calendar calendar = new GregorianCalendar();
		
		calendar.setTime(this.current);
		int min = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
		int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		
		for (int i = min; i <= max; i++) {
			days.add(monthDateFormatter.format(calendar.getTime()));
			calendar.roll(Calendar.DAY_OF_MONTH, true);
		}
		
		return days;
	}
	
	/**
	 * Creates and returns the search page
	 * 
	 * @return
	 */
	public Page getSearchPage() {
		String name = SEARCH_PAGE;
		Page page = null;
		
		try {
			page = PageConfig.getInstance().getPage(name,
					PMMPageconfigHelper.getPageConfigFile());
		} catch (Exception e) {
			throw new RuntimeException("Search page not found: " + name);
		}
		
		return page;
	}
	
	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.title.PagingForm#getCurrentUrl()
	 */
	public String getCurrentUrl() {
		return query + STARTDATE.toString() + formatter.format(getCurrent());
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.title.PagingForm#getNextUrl()
	 */
	public String getNextUrl() {
		return query + STARTDATE.toString() + formatter.format(getNext());
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.web.title.PagingForm#getPreviousUrl()
	 */
	public String getPreviousUrl() {
		return query + STARTDATE.toString() + formatter.format(getPrevious());
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.web.formbeans.PaginationAndSortingForm#getTable()
	 */
	public Table getTable() {
		/* It's unfortunate that the abstract base class expects a table to be defined... */
		throw new UnsupportedOperationException();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.web.formbeans.PaginationAndSortingForm#setTable(java.lang.String)
	 */
	protected void setTable(String tableId, File configFile) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Returns the end date = start date +/- 1 month
	 * 
	 * @param start
	 * @return
	 */
	private Date getMonth(Date start, int diff) {
		Calendar calendar = new GregorianCalendar();
		
		calendar.setTime(start);
		calendar.add(Calendar.MONTH, diff);
		
		return calendar.getTime();		
	}

	/**
	 * @return the month
	 */
	public String getMonth() {
		return month;
	}

	/**
	 * @param month the month to set
	 */
	public void setMonth(String month) {
		this.month = month;
	}

	/**
	 * @return the year
	 */
	public String getYear() {
		return year;
	}

	/**
	 * @param year the year to set
	 */
	public void setYear(String year) {
		this.year = year;
	}

	/**
	 * @return the spec
	 */
	public String getSpec() {
		return spec;
	}
	
	public void setSpec(String spec) {
		this.spec = spec;
	}
}
