/**
 * ScheduleForm.java
 * Created Jun 2, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.tandbergtv.metadatamanager.model.Field;
import com.tandbergtv.watchpoint.pmm.entities.DistributionSchedule;
import com.tandbergtv.watchpoint.pmm.entities.IAssetList;
import com.tandbergtv.watchpoint.pmm.entities.IContainer;
import com.tandbergtv.watchpoint.pmm.entities.Planner;
import com.tandbergtv.watchpoint.pmm.entities.ProgressItem;
import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.entities.TitleListType;
import com.tandbergtv.watchpoint.pmm.schedule.notify.INotificationGenerator;
import com.tandbergtv.watchpoint.pmm.schedule.notify.Notification;
import com.tandbergtv.watchpoint.pmm.schedule.notify.NotificationGeneratorFactory;
import com.tandbergtv.watchpoint.pmm.title.ITitleService;
import com.tandbergtv.watchpoint.pmm.web.title.TitleProgressBean;
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.web.formbeans.PaginationAndSortingForm;
import com.tandbergtv.workflow.web.table.Table;
import com.tandbergtv.workflow.web.table.TableConfig;

/**
 * Contains a schedule
 * 
 * @author Sahil Verma
 */
public class ScheduleForm extends PaginationAndSortingForm {

	private Schedule schedule;

	private String scheduleId;

	private ScheduleStatistics statistics;

	private String contextId;

	private String date;

	private String sourcePartnerId;

	private Collection<PartnerBean> sources;

	private Collection<PartnerBean> destinations;

	private PartnerBean source;

	private PartnerBean destination;

	private Table table;

	private String[] selectedTitles;

	private String status;

	private String spec;

	/**
	 * 
	 */
	private static final long serialVersionUID = -8393735592997672089L;

	private static String CONTAINER_CACHE_SERVICE_NAME = "Container Cache";

	/**
	 * Creates a ScheduleForm
	 */
	public ScheduleForm() {
	}

	/**
	 * @return the schedule
	 */
	public Schedule getSchedule() {
		return this.schedule;
	}

	/**
	 * @param schedule the schedule to set
	 */
	public void setSchedule(Schedule schedule) {
		this.schedule = schedule;
		Long id = schedule.getSourcePartnerID();

		if (id != null) {
			/* FIXME Why the hell am I storing this information in two places? */
			setSourcePartnerId(id.toString());

			if (this.sources != null) {
				for (PartnerBean partner : this.sources) {
					if (id.equals(partner.getId()))
						this.source = partner;
				}
			}
		}

		if (schedule instanceof DistributionSchedule) {
			DistributionSchedule d = DistributionSchedule.class.cast(schedule);

			setContextId(d.getContextID().toString());
			setDate(CommonUtils.formatDate(d.getPitchDate()));

			// set the destination partner.
			ICacheService<IContainer> containerCache = (ICacheService<IContainer>) ServiceRegistry
					.getDefault().lookup(CONTAINER_CACHE_SERVICE_NAME);
			// container cannot be null at this point. This could be a partner or service
			IContainer container = containerCache.get(d.getContextID());
			PartnerBean destPartner = new PartnerBean(container.getContainerId(), container
					.getContainerName(), d.getContextID());
			this.destination = destPartner;
		} else if (schedule instanceof Planner) {
			Planner planner = Planner.class.cast(schedule);

			setDate(CommonUtils.formatDate(planner.getArrivalDate()));
		}
	}

	/**
	 * @return the scheduleId
	 */
	public String getScheduleId() {
		return this.scheduleId;
	}

	/**
	 * @param scheduleId the scheduleId to set
	 */
	public void setScheduleId(String id) {
		this.scheduleId = id;
	}

	/**
	 * @return the statistics
	 */
	public ScheduleStatistics getStatistics() {
		return this.statistics;
	}

	/**
	 * @param statistics the statistics to set
	 */
	public void setStatistics(ScheduleStatistics statistics) {
		this.statistics = statistics;
	}

	/**
	 * @return the contextId
	 */
	public String getContextId() {
		return this.contextId;
	}

	/**
	 * @param contextId the contextId to set
	 */
	public void setContextId(String contextId) {
		this.contextId = contextId;
	}

	/**
	 * @return the date
	 */
	public String getDate() {
		return this.date;
	}

	/**
	 * @param date the date to set
	 */
	public void setDate(String pitchDate) {
		this.date = pitchDate;
	}

	/**
	 * @return the sourcePartnerId
	 */
	public String getSourcePartnerId() {
		return this.sourcePartnerId;
	}

	/**
	 * @param sourcePartnerId the sourcePartnerId to set
	 */
	public void setSourcePartnerId(String sourcePartnerId) {
		this.sourcePartnerId = sourcePartnerId;
	}

	/**
	 * @return the sources
	 */
	public Collection<PartnerBean> getSources() {
		return this.sources;
	}

	/**
	 * @param sources the sources to set
	 */
	public void setSources(Collection<PartnerBean> sources) {
		this.sources = sources;
	}

	/**
	 * @return the destinations
	 */
	public Collection<PartnerBean> getDestinations() {
		return this.destinations;
	}

	/**
	 * @param destinations the destinations to set
	 */
	public void setDestinations(Collection<PartnerBean> destinations) {
		this.destinations = destinations;
	}

	/**
	 * @return the source
	 */
	public PartnerBean getSource() {
		return this.source;
	}

	/**
	 * @param source the source to set
	 */
	public void setSource(PartnerBean source) {
		this.source = source;
	}

	/**
	 * @return the destination
	 */
	public PartnerBean getDestination() {
		return this.destination;
	}

	/**
	 * @param destination the destination to set
	 */
	public void setDestination(PartnerBean destination) {
		this.destination = destination;
	}

	/**
	 * Determines whether this is a planner
	 * 
	 * @return
	 */
	public boolean getIsPlanner() {
		return (this.schedule instanceof Planner);
	}

	/**
	 * Determines whether this is a pitch schedule
	 * 
	 * @return
	 */
	public boolean getIsDistributionSchedule() {
		return (this.schedule instanceof DistributionSchedule);
	}

	/**
	 * Returns the title beans, each of which is just a wrapper around the title in this schedule
	 * 
	 * @return
	 */
	public Collection<TitleProgressBean> getTitles() {
		NotificationGeneratorFactory factory = NotificationGeneratorFactory.newInstance();
		Collection<TitleProgressBean> list = new ArrayList<TitleProgressBean>();
		INotificationGenerator generator = factory.newGenerator(schedule);
		Notification notification = generator.getNotification(schedule);

		for (Title title : this.schedule.getTitles()) {
			Schedule planner = null;
			Collection<ProgressItem> items = null;

			if (this.schedule.getType() == TitleListType.PITCH) {
				planner = this.findPlanner(title);
				items = this.getProgressItemsForPitch(title, planner);
			} else {
				items = this.schedule.getProgressItems(title);
			}

			/* Build the TitleProgressBean */
			ITitleService service = (ITitleService) ServiceRegistry
					.getDefault().lookup(ITitleService.class);
			Collection<Field> titleFields = service.getAllDecendantFields(title.getId());
			TitleProgressBean progress = new TitleProgressBean(title, items);
			progress.setTitleFields(titleFields);
			if (planner != null) {
				Long partnerId = planner.getSourcePartnerID();
				PartnerBean plannerSource = null;
				if (this.sources != null) {
					for (PartnerBean partner : this.sources) {
						if (partnerId.equals(partner.getId()))
							plannerSource = partner;
					}
				}
				progress.addPlanner(planner, plannerSource);
			}

			if (notification != null) {
				for (Title t : notification.getTitles()) {
					if (t.equals(title))
						progress.setHasAlert(true);
				}
			}

			list.add(progress);
		}

		Collections.sort((List<TitleProgressBean>) list);
		return list;
	}

	/* Go through the Planners associated with the titles and find the most recent planner */
	private Schedule findPlanner(Title title) {
		Schedule planner = null;

		for (IAssetList assetlist : title.getTitlelists()) {
			Schedule schedule = Schedule.class.cast(assetlist);
			if (schedule.getType() == TitleListType.PLANNER) {
				if (!schedule.getDate().after(this.schedule.getDate())) {
					if (planner == null || planner.getDate().before(schedule.getDate())) {
						planner = schedule;
					}
				}
			}
		}

		return planner;
	}

	/* Get all the Progress Items that need to be associated with this title */
	private Collection<ProgressItem> getProgressItemsForPitch(Title title, Schedule planner) {
		Collection<ProgressItem> progressItems = new ArrayList<ProgressItem>();

		/* Get all Progress Items associated with the planner first */
		if (planner != null) {
			for (ProgressItem progressItem : title.getProgressItems()) {
				if (planner.getId().equals(progressItem.getAssetListId()))
					progressItems.add(progressItem);
			}
		}

		/* Get Progress Items associated with current schedule or with no schedule */
		for (ProgressItem progressItem : title.getProgressItems()) {
			Long assetListId = progressItem.getAssetListId();
			if (assetListId == null || schedule.getId().equals(assetListId)) {
				progressItems.add(progressItem);
			}
		}

		return progressItems;
	}

	/**
	 * Returns the number of titles
	 * 
	 * @return
	 */
	public int getNumberOfTitles() {
		return this.schedule.getTitles().size();
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.web.formbeans.PaginationAndSortingForm#getTable()
	 */
	public Table getTable() {
		return this.table;
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.workflow.web.formbeans.PaginationAndSortingForm#setTable(java.lang.String)
	 */
	protected void setTable(String tableId, File configFile) {
		Map<String, String> properties = new HashMap<String, String>();
		properties.put("specificationName", this.getSpec());
		
		this.table = TableConfig.getInstance().getTable(tableId, configFile, properties);
	}

	/**
	 * Workaround for the fact the setTable is not public
	 * 
	 * @param tableId
	 */
	public void setTableId(String tableId, File configFile) {
		setTable(tableId, configFile);
	}

	/**
	 * @return the selectedTitles
	 */
	public String[] getSelectedTitles() {
		return this.selectedTitles;
	}

	/**
	 * @param selectedTitles the selectedTitles to set
	 */
	public void setSelectedTitles(String[] selectedTitles) {
		this.selectedTitles = selectedTitles;
	}

	/**
	 * @return the status
	 */
	public String getStatus() {
		return this.status;
	}

	/**
	 * @param status the status to set
	 */
	public void setStatus(String status) {
		this.status = status;
	}

	/**
	 * @return the spec
	 */
	public String getSpec() {
		return spec;
	}

	/**
	 * @param spec the spec to set
	 */
	public void setSpec(String spec) {
		this.spec = spec;
	}
}
