/*
 * Created on Jul 16, 2008 (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.watchpoint.pmm.action.schedule.distribution;

import java.io.File;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

import com.tandbergtv.watchpoint.pmm.action.ActionException;
import com.tandbergtv.watchpoint.pmm.util.TemplateProperties;

/**
 * Action Handler that converts the generated Pitch Schedule File in internal format to the
 * appropriate output format required for distribution.
 * 
 * @author Vijay Silva
 */
public class ConvertSchedule implements ActionHandler {

	/* Serialization UID */
	private static final long serialVersionUID = -2010585835339235740L;

	/* Property Name for the file extension to use for the distribution file */
	private static final String OUTPUT_FILE_EXTENSION_PROPERTY = "ScheduleDistribution.ConvertedFileExtension";

	/* Property Name for the Schedule Transformer Implementation to use for conversion */
	private static final String SCHEDULE_TRANSFORMER_PROPERTY = "ScheduleDistribution.ScheduleTransformerClassName";

	/**
	 * Convert the internal format schedule file to the output format required for distribution
	 * 
	 * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
	 */
	public void execute(ExecutionContext executionContext) throws ActionException {
		try {
			this.convertSchedule(executionContext);
		} catch (ActionException e) {
			executionContext.setVariable(Variables.PROCESS_FAILURE_REASON, e.getMessage());
			throw e;
		} catch (Exception e) {
			String msg = "Failed to convert the schedule file from internal format to "
					+ "expected distribution format, error: " + e.getMessage();
			executionContext.setVariable(Variables.PROCESS_FAILURE_REASON, msg);
			throw new ActionException(msg, e);
		}
	}

	private void convertSchedule(ExecutionContext context) throws ActionException {
		/* Update the output file path to contain the appropriate extension */
		this.updateOutputFilePath(context);

		/* Build the files for the internal and distribution formats for schedule */
		String inputPath = this.getStringValue(context, Variables.SCHEDULE_FILE_PATH_INTERNAL);
		String outputPath = this.getStringValue(context, Variables.SCHEDULE_FILE_PATH_DISTRIBUTION);
		File sourceFile = new File(inputPath);
		File resultFile = new File(outputPath);

		/* Transform the schedule */
		IScheduleTransformer transformer = this.getScheduleTransformer();
		
		/* Set the generated file name variable */
		String generatedFileName = resultFile.getName();
		context.setVariable(Variables.GENERATED_FILE_NAME, generatedFileName);
		try {
			transformer.transform(sourceFile, resultFile);
		} catch (ScheduleTransformException e) {
			String msg = "Failed to transform the schedule file to the required output format"
					+ ", error: " + e.getMessage();
			throw new ActionException(msg, e);
		}
	}

	/* Get the Schedule Transformer implementation to use for transformation */
	private IScheduleTransformer getScheduleTransformer() throws ActionException {
		String className = TemplateProperties.getString(SCHEDULE_TRANSFORMER_PROPERTY);
		Object instance = null;
		try {
			ClassLoader loader = this.getClass().getClassLoader();
			Class<?> refClass = loader.loadClass(className);
			instance = refClass.newInstance();
		} catch (Exception ex) {
			String msg = "Failed to create instance of Schedule Transformer class: " + className
					+ ", error: " + ex.getMessage();
			throw new ActionException(msg, ex);
		}

		if (!(instance instanceof IScheduleTransformer)) {
			String msg = "The Schedule Transformer class: " + className
					+ " does not implement the required interface: "
					+ IScheduleTransformer.class.getName();
			throw new ActionException(msg);
		}

		return (IScheduleTransformer) instance;
	}

	/* Prepare the Extension to use for the output schedule file */
	private void updateOutputFilePath(ExecutionContext context) {
		String extension = TemplateProperties.getString(OUTPUT_FILE_EXTENSION_PROPERTY);
		if (!extension.startsWith("."))
			extension = "." + extension;

		/* Get the current output path and update the path to contain the extension */
		String outputPath = this.getStringValue(context, Variables.SCHEDULE_FILE_PATH_DISTRIBUTION);
		outputPath += extension;
		context.setVariable(Variables.SCHEDULE_FILE_PATH_DISTRIBUTION, outputPath);
	}

	/* Get the String value for a variable */
	private String getStringValue(ExecutionContext context, String name) {
		Object value = context.getVariable(name);
		return (value != null) ? value.toString() : null;
	}
}
