package com.tandbergtv.workflow.adaptor.handler;


import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.tandbergtv.workflow.adaptor.conf.IHandlerConfiguration;
import com.tandbergtv.workflow.message.HTTPAttachment;
import com.tandbergtv.workflow.message.HTTPMessage;
import com.tandbergtv.workflow.message.HTTPPayload;
import com.tandbergtv.workflow.message.IMessage;
import com.tandbergtv.workflow.message.util.WFSMessageConstants;
import com.tandbergtv.workflow.util.XMLDocumentUtility;

/**
 * Converts the AMS Get Asset Details Async Response's list parameters to simple parameters.
 * 
 * @author Raj Prakash
 * 
 */
public class AMSAssetDetailsResponseHandler extends AbstractHandler
{
	private static final Logger logger = Logger.getLogger(AMSAssetDetailsResponseHandler.class);

	/**
	 * Default Constructor
	 */
	public AMSAssetDetailsResponseHandler()
	{
	}

	/**
	 * @param conf
	 *            The Handler Configuration
	 */
	public AMSAssetDetailsResponseHandler(IHandlerConfiguration conf)
	{
		super(conf);
	}

	/**
	 * @see com.tandbergtv.workflow.adaptor.handler.IHandler#process(com.tandbergtv.workflow.message.IMessage)
	 */
	public IMessage process(IMessage msg) throws HandlerException
	{
		logger.debug("Processing message: " + msg);

		String messageContent = msg.getPayload().getContent();
		try {
			messageContent = transformMessage(messageContent);
		} catch(Exception e) {
			throw new HandlerException("Cannot convert list parameters to simple parameters. Message Content: " + messageContent, e);
		}
		
		IMessage result = this.constructMessage(messageContent, msg);
		logger.debug("Processed Message: " + result);

		return result;
	}

	/**
	 * @see com.tandbergtv.workflow.adaptor.handler.IHandler#postProcess(com.tandbergtv.workflow.message.IMessage)
	 */
	public IMessage postProcess(IMessage msg) throws HandlerException
	{
		return msg;
	}

	/*
	 * Convert list parameters to simple parameters
	 */
	private String transformMessage(String message) throws Exception {
		Document doc = XMLDocumentUtility.loadXml(message);
		XPath xpath = XPathFactory.newInstance().newXPath();
		Node wfsMessageNode = (Node) xpath.evaluate("//WFSMessage", doc, XPathConstants.NODE);
		NamedNodeMap attributes = wfsMessageNode.getAttributes();
		Node typeAttribute = attributes.getNamedItem(WFSMessageConstants.TYPE);
		
		if(typeAttribute != null && typeAttribute.getNodeValue().equals("ack")) {
			String title = getListParameter(xpath, doc, "Title");
			String titleBrief = getListParameter(xpath, doc, "Title_Brief");
			String licenseStart = getListParameter(xpath, doc, "Licensing_Window_Start");
			String licenseEnd = getListParameter(xpath, doc, "Licensing_Window_End");
			String hdContent = getListParameter(xpath, doc, "HDContent");
			String description = getListParameter(xpath, doc, "Description");

			//remove list parameters
			removeListParameters(xpath, doc);

			Node parameterListNode = (Node) xpath.evaluate("//WFSMessage/MessageBody/ParameterList", doc, XPathConstants.NODE);
			
			createAndAddWPCLParamElement(doc, parameterListNode, "Title", title); 
			createAndAddWPCLParamElement(doc, parameterListNode, "Title_Brief", titleBrief); 
			createAndAddWPCLParamElement(doc, parameterListNode, "Licensing_Window_Start", licenseStart); 
			createAndAddWPCLParamElement(doc, parameterListNode, "Licensing_Window_End", licenseEnd); 
			createAndAddWPCLParamElement(doc, parameterListNode, "HDContent", hdContent); 
			createAndAddWPCLParamElement(doc, parameterListNode, "Description", description); 
		}

		IHandlerConfiguration conf = getConfiguration();
		String command = conf.getParameterValue("COMMAND");
		logger.debug("command=" + command);
		if (command == null || command.equals(""))
			command = "null";
		wfsMessageNode.appendChild(createCommandParameter(doc, command));
		return XMLDocumentUtility.convertToString(doc);
	}
	
	/*
	 * Get list parameter value, given the name
	 */
	private String getListParameter(XPath xpath, Document doc, String paramName) throws XPathExpressionException {
		return (String) xpath.evaluate("//List/ListItem[Parameter/Value='" + paramName + "']/Parameter[@Name='value']/Value", doc, XPathConstants.STRING);
	}
	
	/*
	 * Removes the list parameters
	 */
	private void removeListParameters(XPath xpath, Document doc) throws XPathExpressionException {
		NodeList listNodes = (NodeList) xpath.evaluate("//WFSMessage/MessageBody/ParameterList/List", doc, XPathConstants.NODESET);
		if(listNodes != null) {
			for(int i=0; i<listNodes.getLength(); ++i) {
				Node listNode = listNodes.item(i);
				listNode.getParentNode().removeChild(listNode);
			}
		}
	}
	
	/*
	 * Creates a simple parameter with the given name & value and adds to the given parameterListNode
	 */
	private void createAndAddWPCLParamElement(Document doc, Node parameterListNode, String name, String value) {
		Element paramElement = doc.createElement(WFSMessageConstants.PARAMETER);
		paramElement.setAttribute(WFSMessageConstants.PARAMETER_DATA_TYPE, "String");
		paramElement.setAttribute(WFSMessageConstants.PARAMETER_NAME, name);
		Element valueElement = doc.createElement(WFSMessageConstants.PARAMETER_VALUE);
		valueElement.setTextContent(value);
		paramElement.appendChild(valueElement);
		parameterListNode.appendChild(paramElement);
	}
	
	/*
	 * Creates command parameter to the WPCL message
	 */
	private Element createCommandParameter(Document doc, String commandName) {
		Element commandElement = doc.createElement(WFSMessageConstants.COMMAND);
		commandElement.setAttribute(WFSMessageConstants.PARAMETER_NAME, commandName);
		return commandElement;
	}
	
	/*
	 * Constructs a HTTP Message given the original message, and the new message content
	 */
	private HTTPMessage constructMessage(String content, IMessage originalMessage)
	{
		HTTPPayload payload = new HTTPPayload(content);
		HTTPAttachment attachment = null;
		if(originalMessage.getAttachment() != null)
		{
			Object attachContent = originalMessage.getAttachment().getContent();
			String attachType = originalMessage.getAttachment().getContentType();
			attachment = new HTTPAttachment(attachContent, attachType);
		}

		return new HTTPMessage(payload, attachment);
	}
	
}
