/*
 * Created on Jun 30, 2008 (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.watchpoint.pmm.action.asset.arrival;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

/**
 * Update the variables required by the loop that performs the file mapping to a Title. The loop
 * needs to iterate through each of the files in the extracted content folder.
 * 
 * @author Vijay Silva
 */
public class UpdateLoopVariables implements ActionHandler {

	/* Serialization UID */
	private static final long serialVersionUID = 4860895485280005433L;

	// The metadata file extension
	private static final String METADATA_FILE_EXTENSION = ".xml";

	/* The list of file extensions that are filtered when determining the content files */
	private static final String[] FILTERED_EXTENSIONS = 
		new String[] { METADATA_FILE_EXTENSION, ".dtd" };

	/* The Logger */
	private static final Logger logger = Logger.getLogger(UpdateLoopVariables.class);

	/**
	 * Update the variables used by the Loop for Mapping Assets for a Title.
	 * @throws IOException 
	 * 
	 * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
	 */
	public void execute(ExecutionContext context) throws IOException {
		String contentPath = this.getStringValue(context, Variables.STAGING_PATH);
		File contentFolder = new File(contentPath);

		List<String> fileNameList;
		String mapFileNames = getStringValue(context, Variables.MAPFILE_NAMES);

		if(mapFileNames != null) {
			fileNameList = convertCommaSepListtoList(mapFileNames);
		} else {
			String[] fileNames = contentFolder.list();
			if (fileNames == null) {
				throw new IOException("Unable to get list of files for directory: "
						+ contentFolder);
			}

			/* Get metadata file name all the asset file names in the extracted content folder */
			fileNameList = new ArrayList<String>();
			String metadataFileName = null;
			for (String fileName : fileNames) {
				if(isMetadataFile(fileName))
					metadataFileName = fileName;
				else if (isContentFile(fileName))
					fileNameList.add(fileName);
			}
			
			// Add metadata file, if available, as the first item in the list
			if(metadataFileName != null)
				fileNameList.add(0, metadataFileName);
			
			context.setVariable(Variables.MAPFILE_NAMES, convertListToCommaSepList(fileNameList));
		}
		
		
		/* Get the variables required by the loop */
		int loopIndex = this.getIntegerValue(context, Variables.MAPPING_LOOP_INDEX, -1) + 1;
		String fileName = fileNameList.get(loopIndex);
		String filePath = new File(contentFolder, fileName).getAbsolutePath();
		boolean hasMoreFiles = (loopIndex + 1 < fileNameList.size());

		/* Set the values for the loop variables in the context */
		context.setVariable(Variables.MAPPING_LOOP_PATH, filePath);
		context.setVariable(Variables.MAPPING_LOOP_INCOMPLETE, hasMoreFiles);
		context.setVariable(Variables.MAPPING_LOOP_INDEX, loopIndex);
		context.setVariable(Variables.FILE_COUNT, new Integer(fileNameList.size()));
	}

	/* Converts a list of string values to a comma separated list */
	private String convertListToCommaSepList(List<String> list) {
		StringBuffer commaSepListSB = new StringBuffer();
		boolean firstTime = true;
		for(String s : list) {
			if(firstTime) {
				firstTime = false;
			} else {
				commaSepListSB.append(",");
			}
			commaSepListSB.append(s);
		}
		return commaSepListSB.toString();
	}
	
	/* Converts a comma separated list to a list of string values */
	private List<String> convertCommaSepListtoList(String commaSepList) {
		return Arrays.asList(commaSepList.split(","));
	}
	
	/* Determine if the file name qualifies as a metadata file */
	private boolean isMetadataFile(String fileName) {
		if(fileName == null)
			return false;
		
		return fileName.toLowerCase().endsWith(METADATA_FILE_EXTENSION);
	}

	/* Determine if the file name qualifies as a content file */
	private boolean isContentFile(String fileName) {
		if (fileName == null)
			return false;

		String fileNameLowerCase = fileName.toLowerCase();
		for (String filteredExtension : FILTERED_EXTENSIONS) {
			if (fileNameLowerCase.endsWith(filteredExtension))
				return false;
		}

		return true;
	}

	/*
	 * 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;
	}

	/*
	 * Get the integer value for a variable, or default value if the variable does not exist or is
	 * not an integer value.
	 */
	private int getIntegerValue(ExecutionContext context, String variableName, int defaultValue) {
		int intValue = defaultValue;

		Object value = context.getVariable(variableName);
		if (value == null) {
			intValue = defaultValue;
		} else if (value instanceof Integer) {
			intValue = ((Integer) value).intValue();
		} else {
			try {
				intValue = Integer.parseInt(value.toString());
			} catch (NumberFormatException e) {
				logger.warn("Failed to parse value: " + value
						+ " to an integer when getting Asset Mapping Loop Index, "
						+ "using default value: " + defaultValue, e);
			}
		}

		return intValue;
	}
}
