/**
 * GenerateMetadataMessageHandler.java
 * Created on Apr 14, 2009
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.contentmgmt.communication.handlers;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Map;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

import com.tandbergtv.cms.portal.util.transaction.Transactional;
import com.tandbergtv.metadatamanager.factoryImpl.SpecHandlerFactory;
import com.tandbergtv.metadatamanager.model.Asset;
import com.tandbergtv.metadatamanager.model.Spec;
import com.tandbergtv.metadatamanager.spec.IIdentifier;
import com.tandbergtv.metadatamanager.spec.ISpecHandler;
import com.tandbergtv.watchpoint.communication.Util;
import com.tandbergtv.watchpoint.pmm.communication.HandlerErrorCode;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandler;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandlerException;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.title.ITitlePersistenceService;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.message.IMessageKey;
import com.tandbergtv.workflow.message.IMessageUID;
import com.tandbergtv.workflow.message.WorkflowMessage;
import com.tandbergtv.workflow.message.WorkflowMessage.MessageType;

/**
 * @author Vlada Jakobac
 *
 */
public class GenerateMetadataMessageHandler implements MessageHandler {

	private static final String RESULT = "result";
	private static final String SUCCESS = "SUCCESS";
	private static final String OUTPUT_METADATA_FILE_PATH = "outputMetadataFilePath";
	private static final String SPEC = "spec";
	private static final String TITLE_ID = "titleId";
	
	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.communication.MessageHandler#handleMessage(com.tandbergtv.workflow.message.WorkflowMessage)
	 */
	@Override
	@Transactional
	public WorkflowMessage handleMessage(WorkflowMessage message)
			throws Exception {
		
		Util.validateRequired(message, TITLE_ID, SPEC, OUTPUT_METADATA_FILE_PATH);
		
		/* Get the title Id */
		Long titleId = Util.getLongValue(message, TITLE_ID);

		/* Get the Service Registry to allow fetching of the title */
		ServiceRegistry registry = ServiceRegistry.getDefault();
		ITitlePersistenceService service = registry.lookup(ITitlePersistenceService.class);

		/* Get the Title using the Service */
		Title title = null;
		try {
			title = service.get(titleId);
		} catch (Exception e) {
			String msg = "Failed to read the Title from the persistence service, error: "
					+ e.getMessage();
			throw new MessageHandlerException(HandlerErrorCode.OBJECT_NOT_PRESENT, msg, e);
		}

		if (title == null) {
			String msg = "Did not get a Title from the persistence service.";
			throw new MessageHandlerException(HandlerErrorCode.OBJECT_NOT_PRESENT, msg);
		}

		/* Get the matching asset from the title */
		Asset groupAsset = title.getAsset();
		if (groupAsset == null) {
			String msg = "Did not get a group object for a given title.";
			throw new MessageHandlerException(HandlerErrorCode.OBJECT_NOT_PRESENT, msg);
		}
		
		/* Get the spec */
		String spec = Util.getStringValueTrimmed(message, SPEC);
		ISpecHandler specHandler = getSpecHandler(spec);
		if (specHandler == null) {
			String msg = "Did not get a spec handler for a given spec.";
			throw new MessageHandlerException(HandlerErrorCode.OBJECT_NOT_PRESENT, msg);
		}
		IIdentifier id = specHandler.extractId(groupAsset);
		if (!id.isValidIdentifier()) {
			Map<String, String> map = id.getSpecIdentifiers();
			String missingIdentifiers = "";
			for (String key : map.keySet()){
				String value = map.get(key);
				if (value == null || value.equals("")){
					if (missingIdentifiers.length() == 0) {
						missingIdentifiers = key;						
					} else 
						missingIdentifiers += ", " + key;
				}
					 
			}
			String errorMessage = "Title [id=" + title.getId() + "] has no value specified for the following path(s): " + missingIdentifiers;
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, errorMessage);
		}
			
		Document doc = specHandler.get(id);
		
		String outputMetadataFilePath = Util.getStringValueTrimmed(message, OUTPUT_METADATA_FILE_PATH);
		File outputFile = new File (outputMetadataFilePath);
		
		saveXMLDocument(doc, outputFile);
		
		/* Build the response Workflow Message */
		IMessageUID uid = message.getMessageUID();
		IMessageKey key = message.getKey();
		WorkflowMessage response = new WorkflowMessage(uid, key, MessageType.ack); 
		response.putValue(RESULT, SUCCESS);
		
		return response;


	}

	//TODO - must be changed to support pluggable specs
	protected ISpecHandler getSpecHandler(String spec) {
		return SpecHandlerFactory.getInstance(Spec.valueOf(spec.toUpperCase()));
	}
	
	private void saveXMLDocument(Document document, File xmlFile) throws MessageHandlerException {
		OutputStream outputStream = null;
		try {
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer transformer = factory.newTransformer();

			/* Setting pretty formatting properties for output XML  */
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

			String xmlEncoding = document.getXmlEncoding();
			if (xmlEncoding != null)
				transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding);

			outputStream = new FileOutputStream(xmlFile);
			transformer.transform(new DOMSource(document), new StreamResult(outputStream));
		} catch (Exception e) {
			String message = "Failed to write XML document to file: " + xmlFile;
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, message, e);
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (Exception ex) {
					String message = "Failed to close the output stream for the file: " + xmlFile;
					throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, message, ex);
				}
			}
		}
	}

}
