/**
 * RegisterFileMessageHandler.java
 * Created on Jun 17, 2009
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.communication.handlers;

import com.tandbergtv.cms.portal.util.transaction.Transactional;
import com.tandbergtv.metadatamanager.model.Asset;
import com.tandbergtv.metadatamanager.model.Field;
import com.tandbergtv.metadatamanager.model.FieldName;
import com.tandbergtv.metadatamanager.model.File;
import com.tandbergtv.metadatamanager.model.FileType;
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.ITitleService;
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;

/**
 * Creates and registers DERIVED files 
 *  
 * @author Vlada Jakobac
 * 
 */
public class RegisterFileMessageHandler implements MessageHandler {

	private static final String LOOKUP_KEY_XPATH = "/tns:Fields/tns:CustomFields/tns:CustomField[@name=LookupKey]/@value";
	private static final String MATERIAL_ID_XPATH = "/tns:Fields/tns:CustomFields/tns:CustomField[@name=MaterialId]/@value";
	private static final String ENCODE_PROFILE_XPATH = "/tns:Fields/tns:CustomFields/tns:CustomField[@name=EncodeProfile]/@value";
	private static final String ENCODE_FORMAT_XPATH = "/tns:Fields/tns:CustomFields/tns:CustomField[@name=EncodeFormat]/@value";
	private static final String HEIGHT = "height";
	private static final String WIDTH = "width";
	private static final String FILE_SIZE = "fileSize";
	private static final String MIME_TYPE = "mimeType";
	private static final String FILE_NAME = "fileName";
	private static final String DURATION = "duration";
	private static final String ASPECTRATIO = "aspectratio";
	private static final String BITRATE = "bitrate";
	private static final String RESOLUTION = "resolution";
	private static final String MATERIAL_ID = "materialId";
	private static final String ENCODE_PROFILE = "encodeProfile";
	private static final String ENCODE_FORMAT = "encodeFormat";
	private static final String ORIGINAL_FILE_PATH = "originalFilePath";
	private static final String TITLE_ID = "titleId";
	private static final String FILE_URI = "fileURI";
	private static final String ASSET_ID = "assetId";
	private static final String RESULT = "result";
	private static final String SUCCESS = "SUCCESS";
	private static final String LOOKUP_KEY = "lookupKey";

	/*
	 * (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, FILE_URI, ASSET_ID);

		Long titleId = Util.getLongValue(message, TITLE_ID);
		String fileURI = Util.getStringValueTrimmed(message, FILE_URI);
		Long assetId = Util.getLongValue(message, ASSET_ID);
		String originalFilePath = Util.getStringValueTrimmed(message,
				ORIGINAL_FILE_PATH);

		String encodeFormat = Util
				.getStringValueTrimmed(message, ENCODE_FORMAT);
		String encodeProfile = Util.getStringValueTrimmed(message,
				ENCODE_PROFILE);
		String materialId = Util.getStringValueTrimmed(message, MATERIAL_ID);
		String lookupKey = Util.getStringValueTrimmed(message, LOOKUP_KEY);
		String resolution = Util.getStringValueTrimmed(message, RESOLUTION);
		String bitrate = Util.getStringValueTrimmed(message, BITRATE);
		String aspectratio = Util.getStringValueTrimmed(message, ASPECTRATIO);
		String duration = Util.getStringValueTrimmed(message, DURATION);
		String fileName = Util.getStringValueTrimmed(message, FILE_NAME);
		String mimeType = Util.getStringValueTrimmed(message, MIME_TYPE);
		String fileSize = Util.getStringValueTrimmed(message, FILE_SIZE);
		String width = Util.getStringValueTrimmed(message, WIDTH);
		String height = Util.getStringValueTrimmed(message, HEIGHT);
		String sourceComponentName = Util.getStringValueTrimmed(message, "sourceComponentName");  
		String sourceEntityName = Util.getStringValueTrimmed(message, "sourceEntityName");
		String sourceId = Util.getStringValueTrimmed(message, "sourceId");

		/* Get the Service Registry to allow fetching of the title */
		ServiceRegistry registry = ServiceRegistry.getDefault();
		ITitleService service = registry
				.lookup(ITitleService.class);

		/* Get the Title using the Service */
		Title title = null;
		try {
			title = service.getTitleForUpdate(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);
		}

		/* Find the asset with the given assetId */
		Asset targetAsset = null;
		if (groupAsset.getId() == assetId)
			targetAsset = groupAsset;
		else {
			for (Asset asset : groupAsset.getAllDescendantItems(false)) {
				if (asset.getId() == assetId) {
					targetAsset = asset;
					break;
				}			
			}
		}
		
		if (targetAsset == null) {
			String msg = "Did not get an item object for a given assetId.";
			throw new MessageHandlerException(
					HandlerErrorCode.OBJECT_NOT_PRESENT, msg);
		}

		/* If there's any file with the same lookupKey, set its lookupKey value to blank */
		if (lookupKey != null && !lookupKey.equals("")){
			for (Asset asset : targetAsset.getAllDescendantItems(true)) {
				if (!(asset instanceof File))
					continue;

				Field lookupKeyField = asset.getFirstField(LOOKUP_KEY_XPATH);
				if (lookupKeyField != null && lookupKeyField.getTypedValue().equals(lookupKey)){
					lookupKeyField.setValue("");					
				}
			}

		}
		
		/* Create a DERIVED file, set its properties, and add it as a child to a file or to an asset */
		File derivedFile = new File();
		derivedFile.setFileType(FileType.DERIVED);
		addField(derivedFile, FieldName.FILE_URL.toString(), fileURI);
		addField(derivedFile, ENCODE_FORMAT_XPATH, encodeFormat);
		addField(derivedFile, ENCODE_PROFILE_XPATH, encodeProfile);
		addField(derivedFile, MATERIAL_ID_XPATH, materialId);
		addField(derivedFile, LOOKUP_KEY_XPATH, lookupKey);
		addField(derivedFile, FieldName.RESOLUTION.toString(),
				resolution);
		addField(derivedFile, FieldName.BITRATE.toString(), bitrate);
		addField(derivedFile, FieldName.ASPECTRATIO.toString(),
				aspectratio);
		addField(derivedFile, FieldName.DURATION.toString(), duration);
		addField(derivedFile, FieldName.FILE_NAME.toString(), fileName);
		addField(derivedFile, FieldName.MIME_TYPE.toString(), mimeType);
		if (fileSize == null || fileSize.equals(""))
			fileSize = new java.io.File(fileURI).length() + "";
		addField(derivedFile, FieldName.FILE_SIZE.toString(), fileSize);
		addField(derivedFile, FieldName.WIDTH.toString(), width);
		addField(derivedFile, FieldName.HEIGHT.toString(), height);

		if (originalFilePath != null){
			/* Find the file whose processed file we want to register */
			File targetFile = null;
			for (Asset asset : targetAsset.getAllDescendantItems(true)) {
				if (!(asset instanceof File))
					continue;

				File file = File.class.cast(asset);
				if (file.getURL().equals(originalFilePath)) {
					targetFile = file;
					break;
				}
			}

			if (targetFile == null) {
				String msg = "Did not find a file object for a given assetId and originalFilePath.";
				throw new MessageHandlerException(
						HandlerErrorCode.OBJECT_NOT_PRESENT, msg);
			}
			
			targetFile.addChild(derivedFile);

		} else {//add it as a child to the given asset
			targetAsset.addChild(derivedFile);
			
		}
		
		service.update(title, sourceComponentName, sourceEntityName, sourceId);
		
		/* 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;
	}

	private void addField(File derivedFile, String path, String value) {
		if (value != null && path != null && !path.trim().isEmpty())
			derivedFile.addField(new Field(path, value));
		
	}

}
