/*
 * Created on Jun 27, 2008 (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.watchpoint.pmm.action.asset.arrival;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

import com.tandbergtv.watchpoint.pmm.action.ActionException;
import com.tandbergtv.watchpoint.pmm.action.ExtractArchiveAction;
import com.tandbergtv.watchpoint.pmm.util.FilePermissionUtility;
import com.tandbergtv.watchpoint.pmm.util.PathProperties;

import de.schlichtherle.io.File;

/**
 * Action that creates a new folder for the received archive file in the configured content folder
 * path for the input provider. Extracts the contents of the archive file, and determines the
 * metadata file path as well and a count of the content files in the archive file.
 * 
 * @author Vijay Silva
 */
public class ExtractPackage extends ExtractArchiveAction implements ActionHandler {

	/* Serialization UID */
	private static final long serialVersionUID = -2720476751762871638L;

	/**
	 * Set the Archive Path and the Target Folder Path
	 * 
	 * @see com.tandbergtv.mmm.action.ExtractArchiveAction#prepareForExtract(org.jbpm.graph.exe.ExecutionContext)
	 */
	@Override
	protected void prepareForExtract(ExecutionContext context) throws ActionException {
		/* Get the Archive Path from the Process Variable */
		this.archivePath = this.getStringValue(context, Variables.PACKAGE_ARCHIVE_PATH);

		/* Get the main content folder and verify that the folder exists */
		String contentPath = PathProperties.getProperty(PathProperties.CONTENT_PATH);
		if (contentPath == null || contentPath.trim().length() == 0) {
			throw new ActionException(
					"The configured content folder does not have a value specified.");
		}

		File contentFile = new File(contentPath);
		if (!contentFile.exists()) {
			throw new ActionException("The configured content folder: "
					+ contentFile.getAbsolutePath() + " does not exist.");
		}

		/* Get the Provider Id and create the Provider Id folder, if not present */
		String providerId = this.getStringValue(context, Variables.PROVIDER_ID);
		if (providerId == null || providerId.trim().length() == 0) {
			throw new ActionException("The Provider Id does not have a value specified.");
		}

		File providerFolder = new File(contentFile, providerId);
		if (!providerFolder.exists() && !providerFolder.mkdir()) {
			throw new ActionException("The content folder for Provider[" + providerId + "]: "
					+ providerFolder.getAbsolutePath() + " could not be created.");
		} 
		
		if (!providerFolder.isDirectory()) {
			throw new ActionException("The content folder for Provider[" + providerId + "]: "
					+ providerFolder.getAbsolutePath() + " is not a folder.");
		}

		/* Build the Asset Path relative to the Provider content folder */
		String originalAssetPath = PathProperties.getProperty(PathProperties.ORIGINAL_ASSET_PATH);
		File originalAssetFolder = new File(providerFolder, originalAssetPath);
		File archiveFile = new File(this.archivePath);
		String name = archiveFile.getName();
		int index = name.lastIndexOf(".");
		if (index != -1) {
			name = name.substring(0, index);
		}

		String packageFolderName = name + "_" + System.currentTimeMillis();
		File packageFolder = new File(originalAssetFolder, packageFolderName);

		/* Create the new package folder */
		if (!packageFolder.mkdirs()) {
			throw new ActionException("Failed to create new content folder: "
					+ packageFolder.getAbsolutePath() + " for extracting archive file: "
					+ this.archivePath);
		}

		this.targetFolderPath = packageFolder.getAbsolutePath();
		context.setVariable(Variables.STAGING_PATH, this.targetFolderPath);
	}

	/**
	 * Verifies that there is exactly one metadata (*.xml) file in the extracted archive.
	 * 
	 * @see com.tandbergtv.mmm.action.ExtractArchiveAction#performPostExtractTasks(org.jbpm.graph.exe.ExecutionContext,
	 *      de.schlichtherle.io.File, de.schlichtherle.io.File)
	 */
	@Override
	protected void performPostExtractTasks(ExecutionContext context, File archiveFile,
			File targetFolder) throws ActionException {
		/* Update the file permission for the entire folder and its children */
		FilePermissionUtility.setPermissions(targetFolder);

		/* Go through the extracted file names, and determine the metadata file */
		int xmlFileCount = 0;
		String[] fileNames = targetFolder.list();
		if (fileNames != null) {
			for (String fileName : fileNames) {
				if (fileName.toLowerCase().endsWith(".xml"))
					xmlFileCount++;
			}
		}

		if (xmlFileCount == 0) {
			throw new ActionException("The archive file: " + this.archivePath
					+ " does not contain a metadata file (with extension '.xml').");
		} else if (xmlFileCount > 1) {
			throw new ActionException("The archive file: " + this.archivePath
					+ " contains more than one file "
					+ "with extension '.xml', failed to determine the metadata file.");
		}
	}

	/*
	 * 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;
	}
}
