/**
 * ScheduleTitlesAction.java
 * Created Jun 4, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import java.io.File;
import java.io.PrintWriter;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.ResourceBundle;

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.action.ActionRedirect;
import org.apache.struts.actions.MappingDispatchAction;
import org.w3c.dom.Node;

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.Planner;
import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.schedule.ISchedulePersistenceService;
import com.tandbergtv.watchpoint.pmm.schedule.ScheduleRuntimeException;
import com.tandbergtv.watchpoint.pmm.schedule.bind.ScheduleMarshaller;
import com.tandbergtv.watchpoint.pmm.schedule.search.IScheduleSearchService;
import com.tandbergtv.watchpoint.pmm.util.XMLDocumentUtility;
import com.tandbergtv.watchpoint.pmm.web.util.PMMTableConfigHelper;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.core.service.cache.ICacheService;

/**
 * This class takes care of the controller functionality for the title basic and activity views
 * of a planner or pitch schedule
 * 
 * @author Sahil Verma
 */
public class ScheduleTitlesAction extends MappingDispatchAction {

	private ISchedulePersistenceService service;
	
	private IScheduleSearchService searchservice;
	
	private static final String TABLE_ID = "scheduletitles";
	
	private static final String ACTIVITY_TABLE_ID = "scheduleactivity";
	
	private static final String PLANNER_TABLE_ID = "planneractivity";
	
	private static final Logger logger = Logger.getLogger(ScheduleTitlesAction.class);
	
	private static final String DATE_FORMAT = "yyyy-MM-dd";
	
	/**
	 * Creates a ScheduleTitlesAction
	 */
	public ScheduleTitlesAction() {
		this.service = ServiceRegistry.getDefault().lookup(ISchedulePersistenceService.class);
		this.searchservice = ServiceRegistry.getDefault().lookup(IScheduleSearchService.class);
	}

	/**
	 * Displays the basic view of a schedule
	 */
	public ActionForward getBasicView(ActionMapping mapping, ActionForm actionform,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		ScheduleForm form = (ScheduleForm)actionform;
		String id = form.getScheduleId();
		Schedule schedule = service.get(Long.parseLong(id));
		
		logger.debug("Schedule " + schedule);
		
		ScheduleFormPopulator.populateScheduleForm(form);
		
		form.setSchedule(schedule);
		form.setStatistics(getScheduleStatistics(schedule));
		form.setTableId(TABLE_ID, PMMTableConfigHelper.getTableConfigFile());
		
		return mapping.findForward("default");
	}
	
	/**
	 * Displays the activity view of a schedule
	 */
	public ActionForward getActivityView(ActionMapping mapping, ActionForm actionform,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		ScheduleForm form = (ScheduleForm)actionform;
		String id = form.getScheduleId();
		Schedule schedule = service.get(Long.parseLong(id));
		
		logger.debug("Schedule " + schedule);
		
		ScheduleFormPopulator.populateScheduleForm(form);
		
		form.setSchedule(schedule);
		form.setStatistics(getScheduleStatistics(schedule));
		
		File configFile = PMMTableConfigHelper.getTableConfigFile();		
		if (schedule instanceof Planner) {
			form.setTableId(PLANNER_TABLE_ID, configFile);
		} else {
			form.setTableId(ACTIVITY_TABLE_ID, configFile);	
		}
		
		return mapping.findForward("default");
	}

	/**
	 * Deletes titles from the schedule
	 */
	public ActionForward deleteTitles(ActionMapping mapping, ActionForm actionform,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		ScheduleForm form = (ScheduleForm)actionform;
		String id = form.getScheduleId();
		Schedule schedule = service.get(Long.parseLong(id));
		
		logger.debug("Schedule " + schedule);
		
		if (form.getSelectedTitles() == null)
			throw new ScheduleRuntimeException("At least one title must be selected");
		
		for (String selected : form.getSelectedTitles()) {
			Long titleId = Long.parseLong(selected);
			logger.debug("Title id " + titleId);
			Title title = schedule.getTitle(titleId);
			
			if (title != null)
				schedule.removeTitle(title);			
		}
		
		service.save(schedule);
		
		ActionRedirect redirect = new ActionRedirect(mapping.findForward("default"));
		
		redirect.addParameter("scheduleId", schedule.getId().toString());
		
		return redirect;
	}
	
	/**
	 * Exports a schedule into its equivalent XML format
	 */
	public ActionForward export(ActionMapping mapping, ActionForm actionform,
		HttpServletRequest request, HttpServletResponse response) throws Exception {
		ScheduleForm form = (ScheduleForm)actionform;
		String id = form.getScheduleId();
		logger.debug("Schedule id " + id);
		
		Schedule schedule = service.get(Long.parseLong(id));
		
		addTransientProperties(schedule);
		
		Node node = ScheduleMarshaller.newInstance().marshal(schedule);
		String xml = XMLDocumentUtility.convertToString(node);
		
		String exportFileName = generateFileName(schedule);
		writeHeaders(response, exportFileName);
		writeScheduleXml(response, xml);
		
		return null;
	}
	
	private String generateFileName(Schedule schedule) {
		String exportFileName = "";
		
		if (schedule instanceof Planner){
			Long partnerId = schedule.getSourcePartnerID();
			exportFileName = getPartner(partnerId).getName();			
		} else if (schedule instanceof DistributionSchedule){
			exportFileName = ((DistributionSchedule)schedule).getPartner();			
		}
		Date scheduleDate = schedule.getDate();
		DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
		exportFileName +=  "_" + formatter.format(scheduleDate) + ".xml";
		return exportFileName;
	}

	/**
	 * @param schedule
	 * @return
	 */
	private ScheduleStatistics getScheduleStatistics(Schedule schedule) {
		String bundle = this.getClass().getPackage().getName() + ".schedule";
		int count = Integer.parseInt(ResourceBundle.getBundle(bundle).getString("history"));
		Collection<Schedule> previous = searchservice.getPreviousSchedules(schedule, count);
		ScheduleStatistics stats = new ScheduleStatistics(schedule, previous);
		
		return stats;
	}
	
	private void addTransientProperties(Schedule schedule) {
		Long partnerId = schedule.getSourcePartnerID();
		
		if (partnerId != null) {
			String providerID = getPartner(partnerId).getProviderId();
			
			schedule.setProviderID(providerID);
		}
		
		Long contextID = schedule.getContextID();
		
		if (schedule instanceof DistributionSchedule) {
			DistributionSchedule d = DistributionSchedule.class.cast(schedule);
			String destination = getDestination(contextID);
			
			d.setPartner(destination);
		}
	}
	
	private void writeHeaders(HttpServletResponse response, String exportFileName) {
		response.setContentType("application/xml");
		
		/* I think this is some kinda hack for IE */
		response.setHeader("Pragma", "public");
		
		/* Don't cache */
		response.setHeader("Cache-Control", "max-age=0");
		
		response.setHeader("Content-Disposition","attachment; filename=" + exportFileName );
	}
	
	private Partner getPartner(Long partnerId) {
		ICacheService<IContainer> cache = 
			(ICacheService<IContainer>)ServiceRegistry.getDefault().lookup("Container Cache");
		
		for (Serializable key : cache.getKeys()) {
			IContainer container = cache.get(key);
			
			if (container.getContainerType() == ContainerType.PARTNER) {
				Partner partner = Partner.class.cast(container);
				
				if (partnerId.longValue() == partner.getId())
					return partner;
			}
		}
		
		throw new RuntimeException("Partner not found: " + partnerId);
	}
	
	private String getDestination(Long contextID) {
		ICacheService<IContainer> cache = 
			(ICacheService<IContainer>)ServiceRegistry.getDefault().lookup("Container Cache");
		IContainer container = cache.get(contextID.longValue());
		
		return container.getContainerName();
	}
	
	private void writeScheduleXml(HttpServletResponse response, String xml) throws Exception {
		PrintWriter out = response.getWriter();
		
		out.write(xml);
		out.println();
		out.close();		
	}
}
