/* Copyright Dassault Systemes, 1999, 2009 */


package examples.development.components.mycommand;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.engineous.sdk.component.DefaultComponentHandler;
import com.engineous.sdk.component.PluginAPI;
import com.engineous.sdk.component.PluginHandler;
import com.engineous.sdk.exception.SDKException;
import com.engineous.sdk.gui.ProgressRange;
import com.engineous.sdk.metamodel.MetaModel;
import com.engineous.sdk.metamodel.MetaModelManager;
import com.engineous.sdk.model.DtModelEvent;
import com.engineous.sdk.model.DtModelManager;
import com.engineous.sdk.model.DtPlugin;
import com.engineous.sdk.model.DtScalarVariable;
import com.engineous.sdk.model.exceptions.DtModelException;
import com.engineous.sdk.validation.ValidationEvent;
import com.engineous.sdk.validation.ValidationResult;
import com.engineous.sdk.vars.EsiTypes;
import com.engineous.sdk.vars.FileValueType;
import com.engineous.sdk.vars.VariableException;
import com.engineous.sdk.version.Version;

/**
 * Example component handler for a component that uses OSCommand as a plugin.
 * The handler is responsible for creating the plugin if it doesn't exist yet,
 * and for forwarding model change and validate events to the plugin.
 */
public class MyCommandHandler
		extends DefaultComponentHandler {

	/**
	 * The name of the OSCommand plugin.  Must be unique among all Plugins to this Component,
	 * but can match be the same as a Parameter or Property name.
	 * All classes in this package reference this one constant for the name.
	 */
	public static final String COMMAND_PLUGIN_NAME = "command";

	/** Keep track of the plugin - it is needed in a lot of places. */
	DtPlugin oscmdPlugin;

	/** The handler for the plugins.  Most plugins don't have handlers, but OSCommand does */
	PluginHandler oscmdHandler;

	/**
	 * Called each time the model is loaded.
	 * If there is no OSCommand plugin yet, create one.  This makes the editor simpler.
	 * @throws SDKException
	 * @see com.engineous.sdk.component.DefaultComponentHandler#addedToModel()
	 */
	public void addedToModel()
			throws SDKException {

		super.addedToModel();

		try {
			// Get or create the OSCommand plugin.
			if (myComponent.hasPlugin(COMMAND_PLUGIN_NAME)) {
				oscmdPlugin = myComponent.getPlugin(COMMAND_PLUGIN_NAME);
			}
			else {
				// Create the OSCommand plugin.
				MetaModel oscmdmm =
					MetaModelManager.instance().lookupMetaModel("com.engineous.plugin.OSCommand",    // Name of plugin MetaModel in the library
					Version.LATEST,                                            // Version to use - use latest always.
					getMetaModel(),                                            // Parent MetaModel for a plugin - which is me.
					myComponent.getModelManager().getLoadedVersionScope());    // Version scope to resolve multiple versions.
				oscmdPlugin = DtModelManager.createPlugin(oscmdmm, COMMAND_PLUGIN_NAME);

				// Do basic configuration of the plugin here.
				PluginAPI oscmdAPI = oscmdPlugin.getAPI();
				// Set up the standard command line to be 'command inputFile'
				// OSCommand API method "quote" produces the proper syntax for inserting a Parameter name into
				// the command line.
				oscmdAPI.set("command", oscmdAPI.call("quote", "command") + " " + oscmdAPI.call("quote", "inputFile"));
				// Make sure standard error is logged and reported as a error.
				oscmdAPI.set("LogStdError", true);
				oscmdAPI.set("FailWhenStdError", true);
				oscmdAPI.apply();

				// Finally add the plugin to my DtComponent.
				myComponent.addPlugin(oscmdPlugin);

				// If you needed a Grid plugin for the OSCommand, here is how you would create and add it.
				/*
				 * MetaModel gridmm = MetaModelManager.instance().lookupMetaModel(
				 *       "com.engineous.plugin.grid.ssh.SshGridPlugin",      // SSH Grid Plugin
				 *       Version.LATEST,
				 *       oscmdmm,                // parent meta-model for grid is OSCommand
				 *       myComponent.getModelManager().getLoadedVersionScope()); // Version scope to resolve multiple versions.
				 * // NOTE plugin name must be GridPlugin.TYPE_NAME in order to be recognized by OSCommand.
				 * DtPlugin gridPlugin = DtModelManager.createPlugin(gridmm, GridPlugin.TYPE_NAME);
				 * oscmdPlugin.addPlugin(gridPlugin);
				 */

				// Configure the two file parameters to reference the same local file.
				// the input file is initially an empty in-model file parameter that saves in 'file.txt'.
				DtScalarVariable inputParam = (DtScalarVariable)myComponent.getParameter("inputFile");
				FileValueType inputValue = (FileValueType)inputParam.getValueObj();
				inputValue.setLocalFileName("file.txt");
				inputValue.setToOption(FileValueType.INPUT_OPTION_FIXED_FILENAME);
				inputValue.setHandlerType(EsiTypes.INLINE_HANDLER);
				inputValue.setDataType(FileValueType.TYPE_TEXT);

				// The output file is Fiper File Manager that reads from "file.txt".
				DtScalarVariable outputParam = (DtScalarVariable)myComponent.getParameter("outputFile");
				FileValueType outputValue = (FileValueType)outputParam.getValueObj();
				outputValue.setToOption(FileValueType.OUTPUT_OPTION_FILEMGR);
				outputValue.setLocalFileName("file.txt");
				outputValue.setDataType(FileValueType.TYPE_TEXT);
			}

			// Now get the plugin's handler and call it's addedToModel method
			// Everyone uses the handler, so save it as a member.
			MetaModel mm = oscmdPlugin.getMetaModel();
			oscmdHandler = (PluginHandler)mm.getHandlerClassInstance(PluginHandler.class);
			oscmdHandler.initHandler(oscmdPlugin);
			oscmdHandler.addedToModel();
		}
		catch (Exception ex) {
			// If anything goes wrong, it is fatal.  Re-throw as an SDKException
			throw new SDKException(ex);
		}

	}

	/**
	 * Get the list of all Parameter names that are currently used by the component or its plugins.
	 * Delegate to
	 * @return
	 * @throws SDKException
	 * @see com.engineous.sdk.component.DefaultComponentHandler#getUsedParameters()
	 */
	public Collection<String> getUsedParameters()
			throws SDKException {

		// Following test is to bullet-proof the code.  It should never happen.
		if (oscmdHandler == null) {
			return null;
		}

		Collection<String> usedParameters = oscmdHandler.getUsedParameters();
		if (usedParameters != null) {
			// Add any parameters used by the Component to the collection.
			// Cannot count of the return from getUsedParameters being a mutable collection, so make a private copy.
			usedParameters = new ArrayList<String>(usedParameters);

			// The two file parameters are always in use.  The OSCommand plugin sees inputFile, but not outputFile
			usedParameters.add("inputFile");
			usedParameters.add("outputFile");
			usedParameters.add("command");
		}
		// If usedParameters is null, we cannot get the list, so just let it return null.

		return usedParameters;
	}

	/**
	 * @param validationList
	 * @throws SDKException
	 * @see com.engineous.sdk.component.DefaultComponentHandler#validate(java.util.List)
	 */
	public void validate(List validationList)
			throws SDKException {

		super.validate(validationList);

		try {
			// For this component, it is an error if parameter inputFile or outputFile is deleted.
			if (!myComponent.hasParameter("inputFile")) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_ERROR, myComponent,
						"Required file parameter inputFile has been deleted."));
			}
			if (!myComponent.hasParameter("outputFile")) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_ERROR, myComponent,
						"Required file parameter outputFile has been deleted."));
			}
			if (!myComponent.hasParameter("command")) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_ERROR, myComponent,
						"Required string parameter command has been deleted."));
			}
		}
		catch (DtModelException ex) {
			// If anything goes wrong, it is fatal.  Re-throw as an SDKException
			throw new SDKException(ex);
		}

		// Note that null test is just to bulletproof the code.  It should never happen.
		if (oscmdHandler != null) {
			// Have the handler validate itself, producing any needed messages.
			oscmdHandler.validate(validationList);
		}

	}

	/**
	 * Handle model change events.  There is nothing to do here.
	 * In a real component this would check for things like parameters being deleted or renamed.
	 * @param event
	 * @throws DtModelException
	 * @throws VariableException
	 * @see com.engineous.sdk.component.DefaultComponentHandler#modelChanged(com.engineous.sdk.model.DtModelEvent)
	 */
	public void modelChanged(DtModelEvent event)
			throws DtModelException, VariableException {
		super.modelChanged(event);
	}

	/**
	 * Model lifecycle method - called once after the model is fully loaded into memory.  This is always after
	 * addedToModel() is called.
	 * @param progress
	 * @throws SDKException
	 * @see com.engineous.sdk.component.DefaultComponentHandler#modelLoaded(com.engineous.sdk.gui.ProgressRange)
	 */
	public void modelLoaded(ProgressRange progress)
			throws SDKException {

		super.modelLoaded(progress);
		if (oscmdHandler != null) {
			oscmdHandler.modelLoaded(progress);
		}

	}
}

