/**
 * ScheduleStatistics.java
 * Created Jun 2, 2008
 * Copyright (c) TANDBERG Television 2007-2008
 */
package com.tandbergtv.watchpoint.pmm.web.schedule;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TimeZone;

import com.tandbergtv.watchpoint.pmm.entities.Schedule;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.entities.TitleStatus;
import com.tandbergtv.watchpoint.pmm.title.ITitleService;
import com.tandbergtv.watchpoint.pmm.title.conf.IRightsManager;
import com.tandbergtv.watchpoint.pmm.title.conf.specs.RightsManagerFactory;
import com.tandbergtv.workflow.core.service.ServiceRegistry;

/**
 * A simple stats display bean
 * 
 * @author Sahil Verma
 */
public class ScheduleStatistics {
	
	private Schedule schedule;
	
	private Collection<Schedule> previous;

	/**
	 * Creates a ScheduleStatistics
	 * @param schedule
	 */
	public ScheduleStatistics(Schedule schedule, Collection<Schedule> previous) {
		this.schedule = schedule;
		this.previous = previous;
	}

	/**
	 * Returns the total number of titles
	 * 
	 * @return
	 */
	public int getTotalTitles() {
		return schedule.getTitles().size();
	}
	
	/**
	 * Returns the number of titles in the NEW state
	 * 
	 * @return
	 */
	public int getNewTitles() {
		int count = 0;
		
		Collection<Title> titles = schedule.getTitles();
		
		for (Title t : titles) {
			if (t.getStatus() == TitleStatus.NEW)
				count++;
		}
		
		return count;
	}
	
	/**
	 * Returns the number of titles in the READY state
	 * 
	 * @return
	 */
	public int getReadyTitles() {
		int count = 0;
		
		Collection<Title> titles = schedule.getTitles();
		
		for (Title t : titles) {
			if (t.getStatus() == TitleStatus.READY)
				count++;
		}
		
		return count;
	}
	
	/**
	 * Returns the number of titles in the APPROVED state
	 * 
	 * @return
	 */
	public int getApprovedTitles() {
		int count = 0;
		
		Collection<Title> titles = schedule.getTitles();
		
		for (Title t : titles) {
			if (t.getStatus() == TitleStatus.APPROVED)
				count++;
		}
		
		return count;
	}
	
	/**
	 * Returns the total run time of all titles in this schedule
	 * 
	 * @return
	 */
	public String getTotalRunTime() {
		long time = getTotalRunTime(schedule.getTitles());
		Date date = new Date(time);
		
		return getFormattedDate(date);
	}
	
	/**
	 * Returns the total duration of titles that are new in this schedule
	 * 
	 * @return
	 */
	public String getTotalNewHours() {
		long time = getTotalRunTime(getCurrentTitles());
		Date date = new Date(time);

		return getFormattedDate(date);
	}
	
	/**
	 * Returns the refresh rate.
	 * 
	 * @return
	 */
	public int getRefreshRate() {
		if (previous == null)
			return 100;

		Collection<Title> titles = getCurrentTitles();
		long tcurrent = getTotalRunTime(titles);
		
		if (tcurrent == 0)
			return 0;
		
		/* Calculate the total duration of the pre-existing content */
		long tprev = 0;
		
		IRightsManager rm = RightsManagerFactory.getRightsManager();
		for (Title title : getExistingTitles()) {
			/* Exclude all content that expires by the pitch date */
			if (rm != null && rm.isLicensed(title, schedule.getDate()))
				tprev += getRunTime(title);
		}
		
		return (int) (tcurrent * 100 / (tprev + tcurrent));
	}
	
	/**
	 * Adds up all unique titles in the previous schedules
	 * 
	 * @return
	 */
	private Collection<Title> getExistingTitles() {
		Set<Title> titles = new HashSet<Title>();
		
		for (Schedule s : previous) {
			for (Title title : s.getTitles()) {
				titles.add(title);
			}
		}
		
		return titles;
	}
	
	/**
	 * Pare down titles in the current schedule that have not been included in previous lists
	 * 
	 * @return
	 */
	private Collection<Title> getCurrentTitles() {
		Collection<Title> titles = new ArrayList<Title>(schedule.getTitles());
		
		for (Schedule s : previous) {
			Iterator<Title> i = titles.iterator();
			
			while (i.hasNext()) {
				Title title = i.next();

				if (s.getTitles().contains(title))
					i.remove();
			}
		}
		
		return titles;
	}
	
	/**
	 * Returns the aggregate run time of the specified titles in msec
	 * 
	 * @param titles
	 * @return
	 */
	private long getTotalRunTime(Collection<Title> titles) {
		long time = 0L;
		
		for (Title title : titles)
			time += getRunTime(title);
		
		return time;
	}
	
	private long getRunTime(Title title) {
		DateFormat formatter = getFormatter();
		long time = 0L;

		// get all fields for this title and lookup the field manually to get
		// the time.
		ITitleService service = (ITitleService) ServiceRegistry.getDefault()
				.lookup(ITitleService.class);
		String fieldValue = com.tandbergtv.watchpoint.pmm.title.TitleUtil
				.getMetadataValue(service.getAllDecendantFields(title.getId().longValue()),
						"/tns:Fields/tns:Duration/tns:Duration", "TITLE");
		// section name and field ttv xpath match and there is a valid value
		if (fieldValue != null && fieldValue.trim().length() > 0) {
			try {
				time = formatter.parse(fieldValue.trim()).getTime();
			} catch (ParseException e) {
				// there was a problem parsing the time, simply return 0
				return time;
			}
			return time;
		} else {
			// no value provided
			return time;
		}
	}
	
	private DateFormat getFormatter() {
		String format = "HH:mm:ss";
		
		DateFormat formatter = new SimpleDateFormat(format);
		
		formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
		
		return formatter;
	}
	
	private String getFormattedDate(Date date) {
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		
		calendar.setTime(date);
		
		Integer day = calendar.get(Calendar.DAY_OF_YEAR) - 1;
		
		if (day == 0)
			return getFormatter().format(date);
		
		if (day == 1)
			return day.toString() + " day";
		
		return day.toString() + " days";
	}
}
