/*
 * Created on Jun 30, 2008 (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.watchpoint.pmm.action.asset.arrival;

import static javax.xml.xpath.XPathConstants.NODE;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPath;
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.Document;
import org.w3c.dom.Element;

import com.tandbergtv.watchpoint.pmm.action.ActionException;

/**
 * Convert the current metadata file to the internal Title XML format.
 * 
 * @author Vijay Silva
 */
public class TitleMetadataConversion implements ActionHandler {

	/* Serialization UID */
	private static final long serialVersionUID = 3564394721967566401L;

	/* The XPath to get the Metadata location node for the root title in the title xml document */
	private static final String METADATA_LOCATION_XPATH = "/title/metadatalocation";

	/* The Resource used for converting ADI to Title XML */
	private static final String ADI_TITLE_XSL_RESOURCE = "/template-actions/adiTitleConverter.xsl";
	
	Logger logger = Logger.getLogger(TitleMetadataConversion.class);

	/**
	 * Converts the Metadata from the current format to the internal Title Format
	 * 
	 * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
	 */
	public void execute(ExecutionContext context) throws Exception {
		/* Get the current metadata file name and path */
		String metadataFilePath = this.getStringValue(context, Variables.METADATA_FILE_PATH);
		File metadataFile = new File(metadataFilePath);
		String name = metadataFile.getName();
		int index = name.lastIndexOf(".");
		if (index != -1) {
			name = name.substring(0, index);
		}

		/* Generate the converted title format metadata file name and path */
		String metadataFileLocation = metadataFile.getParent();
		String titleFileName = name + "_title.xml";
		File convertedTitleFile = new File(metadataFileLocation, titleFileName);

		/* Perform the Conversion */
		this.convertToTitleFormat(context, metadataFile, convertedTitleFile);

		/* Store a variable for the title metadata path */
		context.setVariable(Variables.TITLE_METADATA_PATH, convertedTitleFile.getAbsolutePath());
	}

	/* Convert the Metadata File to the internal Title XML Format */
	private void convertToTitleFormat(ExecutionContext context, File metadataFile, File titleFile)
			throws ActionException {
		Document titleDocument = null;

		/* Transform the XML in the metadata file into the Title XML format */
		try {
			/* Build the Transformer */
			TransformerFactory factory = TransformerFactory.newInstance();
			InputStream stream = this.getClass().getResourceAsStream(ADI_TITLE_XSL_RESOURCE);
			Source xsltSource = new StreamSource(stream);
			Transformer transformer = factory.newTransformer(xsltSource);

			/* Create a new XML document for the Title */
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			titleDocument = builder.newDocument();

			/* Transform the metadata to Title format into the title document */
			Source fileSource = new StreamSource(metadataFile);
			Result domResult = new DOMResult(titleDocument);
			transformer.transform(fileSource, domResult);
		} catch (Exception e) {
			String msg = "Failed to convert the metadata file into the Title XML Document.";
			throw new ActionException(msg, e);
		}

		/* Update the title document to contain the metadata location */
		try {
			/* Use XPath to find the metadata location node */
			XPath xpath = XPathFactory.newInstance().newXPath();
			Element node = (Element) xpath.evaluate(METADATA_LOCATION_XPATH, titleDocument, NODE);

			/* Override the value of the element with current metadata path */
			node.setTextContent(metadataFile.getAbsolutePath());
		} catch (Exception e) {
			String msg = "Failed to update the metadata location in the Title XML document "
					+ "after converting the metadata to Title XML.";
			throw new ActionException(msg, e);
		}
		FileOutputStream fos = null;
		/* Save the Title XML document to the file system */
		try {
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			 fos = new FileOutputStream(titleFile);
			transformer.transform(new DOMSource(titleDocument), new StreamResult(fos));
		} catch (Exception e) {
			throw new ActionException("Failed to write the converted Title XML document to file: "
					+ titleFile.getAbsolutePath(), e);
		}
		finally{
			try{
				if(fos != null)
					fos.close();
			}
			catch(Exception ex){
				logger.warn("Unable to close file stream " , ex);
			}
		}
	}

	/*
	 * Gets the String value of the variable (in case the data type is not string). Uses toString()
	 * for all data types.
	 */
	private String getStringValue(ExecutionContext context, String variableName) {
		Object value = context.getVariable(variableName);
		return (value != null) ? value.toString() : null;
	}
}
