/**
 * SetTitleStatsAction.java
 * Created on Aug 6, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.action.schedule.ingest;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.tandbergtv.watchpoint.pmm.util.TemplateProperties;
import com.tandbergtv.watchpoint.pmm.util.schedule.ingest.FileType;
import com.tandbergtv.watchpoint.pmm.util.schedule.ingest.PlannerConstants;
import com.tandbergtv.watchpoint.pmm.util.schedule.ingest.ProgramListConstants;

/**
 * This class parses the converted planner file (which is in the PMM format) and for each date (if
 * any) counts the number of top level titles and sets the value per date in 'titleStats' variable.
 * 
 * @author spuranik
 * 
 */
public class SetTitleStatsAction implements ActionHandler {

	private static final long serialVersionUID = 1L;
	private static final Logger logger = Logger.getLogger(SetTitleStatsAction.class);

	// these names should match the ones in the template.
	private static String TITLE_STATS = "titleStats";
	private static String CONVERTED_FILE_PATH = "convertedFilepath";

	private static String PMM_DATETIME_FORMAT = "PMM.date.time.format";
	private static String ADI_DATE_FORMAT = "ADI.date.format";

	private static String STATS_DELIMITER = ",";

	private static String FILE_TYPE = "type";
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
	 */
	public void execute(ExecutionContext context) throws Exception {
		String convertedFilepath = (String) context.getVariable(CONVERTED_FILE_PATH);
		FileType type = FileType.getFileType((String) context.getVariable(FILE_TYPE));
		
		String stats = "";
		if (type == FileType.PLANNER) {
			stats = getPlannerTitleStatistics(convertedFilepath);
		} else if (type == FileType.PROGRAM_LIST) {
			stats = getPLTitleStatistics(convertedFilepath);
		}
		context.setVariable(TITLE_STATS, stats);
	}

	/**
	 * @param convertedFilepath
	 * @return
	 */
	private String getPLTitleStatistics(String inputFilepath) {

		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = factory.newDocumentBuilder();

			Document doc = docBuilder.parse(inputFilepath);
			XPath xPath = XPathFactory.newInstance().newXPath();
			NodeList titles = (NodeList) xPath.evaluate(
					ProgramListConstants.PROGRAMLIST_TITLE_XPATH, doc,
					XPathConstants.NODESET);
			return titles.getLength() + " TITLE(S)";
		} catch (XPathExpressionException e) {
			throw new RuntimeException(e);
		} catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Parses the input file to get all planner elements and gets the number of titles for each
	 * planner. A stats string of the format "[date] [titleCount] TITLES" is prepared for each
	 * planner. In case of program list there is no date.
	 * 
	 * @param inputFilepath
	 *            path to a PMM format planner file
	 * @return a string of the form "[date] [titelCount] TITLES"* or an empty string if there were
	 *         no titles.
	 */
	public String getPlannerTitleStatistics(String inputFilepath) {
		StringBuilder sb = new StringBuilder();
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = factory.newDocumentBuilder();
			Document doc = docBuilder.parse(inputFilepath);

			NodeList planners = doc.getElementsByTagName(PlannerConstants.PLANNER_ELEMENT);

			// go thru all the planner elements (one for each date) and get the count
			// of titles for that date.
			for (int i = 0; i < planners.getLength(); i++) {
				Element planner = (Element) planners.item(i);

				// date
				String date = planner.getElementsByTagName(PlannerConstants.PLANNER_DATE_ELEMENT)
						.item(0).getTextContent();

				// title count
				int titleCount = 0;
				XPathFactory xpathFactory = XPathFactory.newInstance();
				XPath xpath = xpathFactory.newXPath();
				NodeList result;
				try {
					XPathExpression expr = xpath.compile(PlannerConstants.PLANNER_TITLE_XPATH);
					result = (NodeList) expr.evaluate(planner, XPathConstants.NODESET);
					titleCount = result.getLength();
				} catch (XPathExpressionException e) {
					// if there is a problem getting title elements, the stats will show 0 titles
					// for this date.
					logger.error("Error while getting title elements from the planner for date: "
							+ date + " : " + e.getMessage());

				}
				if (sb.length() > 0) {
					sb.append(STATS_DELIMITER);
				}
				sb.append(convert(date) + ":" + titleCount + " TITLE(S)");
			}
		} catch (DOMException e) {
			throw new RuntimeException("Error while getting title stats for: " + inputFilepath, e);
		} catch (ParserConfigurationException e) {
			throw new RuntimeException("Error while parsing: " + inputFilepath, e);
		} catch (SAXException e) {
		} catch (IOException e) {
			throw new RuntimeException("Error while getting title stats for: " + inputFilepath, e);
		}
		return sb.toString();
	}

	/**
	 * This method converts a date of the form 'yyyy-MM-dd'T'HH:mm:ss' to 'yyyy-mm-dd'
	 * 
	 * @param date
	 *            date to convert
	 * @return date in the form 'yyyy-mm-dd' or empty string if there was a problem
	 */
	private String convert(String date) {
		if (date == null || date.length() == 0) {
			return "";
		}

		try {
			String adiDateFormat = TemplateProperties.getString(ADI_DATE_FORMAT);
			String pmmTimeFormat = TemplateProperties.getString(PMM_DATETIME_FORMAT);

			SimpleDateFormat from = new SimpleDateFormat(pmmTimeFormat);
			SimpleDateFormat to = new SimpleDateFormat(adiDateFormat);
			return to.format(from.parse(date));
		} catch (ParseException e) {
			String errorMsg = "Error parsing date: " + date + " : " + e.toString();
			logger.error(errorMsg);
			return "";
		}
	}

}
