/**
 * PackageSchedulerDispatcher.java
 * Created on Jul 29, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.workflow.adaptor.dispatcher;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.rmi.RemoteException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.StringTokenizer;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.systinet.wsdl.com.n2bb.manager.webservice.server.SchedulerService;
import com.systinet.wsdl.com.n2bb.manager.webservice.server.SchedulerService_schedule_comN2BbManagerWebserviceCommonServiceException_Fault;
import com.tandbergtv.workflow.adaptor.conf.IDispatcherConfiguration;
import com.tandbergtv.workflow.comm.IDestination;
import com.tandbergtv.workflow.message.IMessage;
import com.tandbergtv.workflow.message.MessageKeyImpl;
import com.tandbergtv.workflow.message.MessageUIDImpl;
import com.tandbergtv.workflow.message.WorkflowMessage;
import com.tandbergtv.workflow.message.WorkflowPayload;
import com.tandbergtv.workflow.message.WorkflowMessage.MessageType;
import com.tandbergtv.workflow.util.XMLDocumentUtility;

/**
 * @author Vlada Jakobac
 * 
 */
public class PackageSchedulerDispatcher extends MediaPathDispatcher {

	private static final Logger logger = Logger
			.getLogger(PackageSchedulerDispatcher.class);

	/* The Date Format for the date present in the message */
	private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss z yyyy";

	public PackageSchedulerDispatcher(IDispatcherConfiguration conf,
			IDestination destination) {
		super(conf, destination);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tandbergtv.workflow.adaptor.dispatcher.MediaPathDispatcher#generateResponse(com.tandbergtv.workflow.message.IMessage,
	 *      java.net.URL)
	 */
	@Override
	protected WorkflowMessage generateResponse(IMessage msg, URL url)
			throws DispatcherException {
		logger.debug("payload=" + msg.getPayload().getContent());
		Document doc;
		try {
			doc = XMLDocumentUtility.loadXml(msg.getPayload().getContent());

			String scheduleDate = null, packageToPitchId = null, encryptPackage = null, pitcherId = null, catcherIdsValues = null;
			XPath xpath = XPathFactory.newInstance().newXPath();
			Node parameterListNode = (Node) xpath.evaluate(
					"//WFSMessage/MessageBody/ParameterList", doc,
					XPathConstants.NODE);
			if (parameterListNode != null) {
				Node scheduleDateNode = (Node) xpath.evaluate(
						"Parameter[@Name='ScheduleDate']", parameterListNode,
						XPathConstants.NODE);
				if (scheduleDateNode != null) {
					scheduleDate = (String) xpath.evaluate("Value",
							scheduleDateNode, XPathConstants.STRING);
				}
				Node packageIdNode = (Node) xpath.evaluate(
						"Parameter[@Name='PackageId']", parameterListNode,
						XPathConstants.NODE);
				if (packageIdNode != null) {
					packageToPitchId = (String) xpath.evaluate("Value",
							packageIdNode, XPathConstants.STRING);
				}
				Node encryptPackageNode = (Node) xpath.evaluate(
						"Parameter[@Name='EncryptPackage']", parameterListNode,
						XPathConstants.NODE);
				if (encryptPackageNode != null) {
					encryptPackage = (String) xpath.evaluate("Value",
							encryptPackageNode, XPathConstants.STRING);
				}
				Node pitcheIdNode = (Node) xpath.evaluate(
						"Parameter[@Name='PitcherId']", parameterListNode,
						XPathConstants.NODE);
				if (pitcheIdNode != null) {
					pitcherId = (String) xpath.evaluate("Value", pitcheIdNode,
							XPathConstants.STRING);
				}
				Node catcherIdsNode = (Node) xpath.evaluate(
						"Parameter[@Name='CatcherIds']", parameterListNode,
						XPathConstants.NODE);
				if (catcherIdsNode != null) {
					catcherIdsValues = (String) xpath.evaluate("Value",
							catcherIdsNode, XPathConstants.STRING);
				}
			}

			Node wfsMessageNode = (Node) xpath.evaluate("//WFSMessage", doc,
					XPathConstants.NODE);

			String messUID = (String) wfsMessageNode.getAttributes()
					.getNamedItem("UID").getTextContent();
			String requestKey = (String) wfsMessageNode.getAttributes()
					.getNamedItem("RequestKey").getTextContent();
			logger.debug("messUID=" + messUID + ", requestKey=" + requestKey);
			WorkflowMessage response = new WorkflowMessage(new MessageUIDImpl(
					messUID), new MessageKeyImpl(requestKey));
			WorkflowPayload payload = (WorkflowPayload) response.getPayload();

			try {
				SchedulerService service = getService(url);
				String pitchId = getPitchId(service, packageToPitchId,
						pitcherId, encryptPackage, catcherIdsValues,
						scheduleDate);

				payload.putValue("PitchId", pitchId);
				response.setType(MessageType.ack);
			} catch (MediaPathAPIException de) {
				logger.error(
						"Error occurred while scheduling pitch of a package: ",
						de);
				StringWriter writer = new StringWriter();
				de.printStackTrace(new PrintWriter(writer));
				payload.putValue("error-message", de.getMessage());
				payload.putValue("error-stack", writer.toString());
				response.setType(MessageType.nack);

			}
			return response;
		} catch (Exception e) {
			throw new DispatcherException(e);
		}
	}

	private String getPitchId(SchedulerService service,
			String packageToPitchId, String pitcherId, String encryptPackage,
			String catcherIdsValues, String scheduleDate)
			throws MediaPathAPIException {
		String pitchId = "";
		// always pitching a single package
		Long[] packageToPitch = new Long[1];
		packageToPitch[0] = Long.valueOf(packageToPitchId);

		long pitcherIdLong = Long.valueOf(pitcherId);
		boolean videoSecure = Boolean.valueOf(encryptPackage);

		Long[] catcherIds = convertCommaSepListToList(catcherIdsValues);
		Long[] pitchIds;
		try {
			// set the pitch date
			DateFormat format = new SimpleDateFormat(DATE_FORMAT);
			Calendar pitchDate = Calendar.getInstance();
			pitchDate.setTime(format.parse(scheduleDate));

			pitchIds = service.schedule(packageToPitch, catcherIds, pitchDate,
					videoSecure, pitcherIdLong);
		} catch (SchedulerService_schedule_comN2BbManagerWebserviceCommonServiceException_Fault e) {
			throw new MediaPathAPIException(e);
		} catch (RemoteException e) {
			throw new MediaPathAPIException(e);
		} catch (ParseException e) {
			throw new MediaPathAPIException(e);
		}
		pitchId = pitchIds[0].toString();

		return pitchId;
	}

	/*
	 * Converts a comma separated list to an array list 
	 */
	private Long[]convertCommaSepListToList(String str) {
		Long[] catcherIds = null;
		if (str != null) {
			StringTokenizer st = new StringTokenizer(str, ",");
			catcherIds = new Long[st.countTokens()];
			int i=-1;
			while (st.hasMoreTokens()) {
				i++;
				catcherIds[i] = Long.valueOf(st.nextToken().trim());
			}
		}
		return catcherIds;
	}

}
