/* Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by Engineous Software Inc.,
 * 2000 CentreGreen Way, Suite 100 Cary, NC 27513, U.S.A
 * All rights reserved.
 *
 * IN NO EVENT SHALL ENGINEOUS SOFTWARE INC. BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
 * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ENGINEOUS
 * SOFTWARE INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ENGINEOUS SOFTWARE INCORPORATED SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND ENGINEOUS SOFTWARE INC. HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

package examples.development.components.plate;

import com.engineous.common.i18n.IString;
import com.engineous.sdk.component.DefaultComponentHandler;
import com.engineous.sdk.exception.SDKException;
import com.engineous.sdk.gui.ProgressRange;
import com.engineous.sdk.metamodel.MetaModel;
import com.engineous.sdk.model.*;
import com.engineous.sdk.model.exceptions.DtModelException;
import com.engineous.sdk.validation.ValidationEvent;
import com.engineous.sdk.validation.ValidationResult;
import com.engineous.sdk.vars.ScalarVariable;
import com.engineous.sdk.vars.Variable;
import com.engineous.sdk.vars.VariableException;
import com.engineous.sdk.vars.VariableUtil;

import java.util.Iterator;

/**
 * This class provides a default implementation for all methods of the ComponentHandler interface.
 * Component developers can extend this class to get default implementations and then
 * override selected methods as needed.  Note that in general, this class implementation
 * should be called in any overridden methods even if the current implementation
 * does nothing.
 * <p>
 * Some simple components may use this class as-is for their component
 * handler and do not have to write an extension to this class at all.
 */

public class PlateHandler
		extends DefaultComponentHandler {

	transient private static final Class CLASS = PlateHandler.class;

	private ScalarVariable shapeProp;
	private ScalarVariable materialProp;
	private ScalarVariable thicknessParam;


	/**
	 * This implementation saves a reference to the properties
	 * @param component
	 * @throws SDKException
	 */
	public void initHandler(DtComponent component)
			throws SDKException {
		super.initHandler(component);
	}

	//=========================================================================
	/**
	 * This method is called when a new Plate component is added to the model
	 * Here, we just get handles to the properties/parameters we will use in the rest
	 * of the Handler
	 * @throws SDKException
	 */
	//=========================================================================
	public void addedToModel()
			throws SDKException {
		getProperties();
	}

	//=========================================================================
	/**
	 * This method is called when a model that has a Plate component is loaded
	 * Here, we just get handles to the properties/parameters we will use in the rest
	 * of the Handler
	 * @param progressRange
	 * @throws SDKException
	 */
	//=========================================================================
	public void modelLoaded(ProgressRange progressRange)
			throws SDKException {
		getProperties();
	}

	//=========================================================================
	/**
	 * Method getProperties
	 * @throws SDKException
	 */
	//=========================================================================
	private void getProperties()
			throws SDKException {

		try {
			shapeProp = ((DtScalarVariable)myComponent.getProperty("Shape"));
			materialProp = ((DtScalarVariable)myComponent.getProperty("Material"));
			thicknessParam = ((DtScalarVariable)myComponent.getParameter("Thickness"));
		}
		catch (Throwable e) {
			throw new SDKException(e, "Error initializing component Handler.");
		}
	}


	/**
	 * Reacts to changes to the pre-defined parameters
	 * @param event
	 * @throws DtModelException
	 * @throws VariableException
	 */
	public void modelChanged(DtModelEvent event)
			throws DtModelException, VariableException {

		// A MODEL_UPDATED type of event is a way to bundle numerous events under
		// a single one so they can all be processed together.  We must account for
		// these here by looping over all of the bundled events and processing each
		if (event.getEventType() == DtModelEvent.MODEL_UPDATED) {
			Iterator eventIter = event.getAccumulatedEvents().iterator();
			while (eventIter.hasNext()) {
				this.modelChanged((DtModelEvent)eventIter.next());
			}
			return;
		}

		DtModelElement dtme = event.getModelElement();

		// Only interested in Variable events for my component
		DtComponent eventComp = event.getParentCompForEvent();
		if ((eventComp == myComponent) && (dtme instanceof Variable)) {

			Variable eVar = (Variable)dtme;

			Variable rootVar = VariableUtil.getRootVariable(eVar);
			String rootVarName = rootVar.getName();

			// if one of our predefined parameter names changes, change it back
			if (event.getChangeType() == DtModelEvent.CHANGED_VARNAME) {
				String oldName = (String)event.getOldValue();
				String newName = VariableUtil.getVariablePathAsString(eVar);

				if (oldName.equals("Dimensions")) {
					((DtVariable)eVar).setName("Dimensions");
				}
				else if (oldName.equals("Area")) {
					((DtVariable)eVar).setName("Area");
				}
				else if (oldName.equals("Volume")) {
					((DtVariable)eVar).setName("Volume");
				}
				else if (oldName.equals("Weight")) {
					((DtVariable)eVar).setName("Weight");
				}
			}


			// if a pre-defined parameter is deleted, add it back
			if (event.getEventType() == DtModelEvent.ELEMENT_REMOVED) {

				String varName = eVar.getName();
				DtVariable dtVar = (DtVariable)eVar;

				if (varName.equals("Dimensions") || varName.equals("Area") || varName.equals("Weight") || varName.equals("Volume")) {
					myComponent.addParameter(dtVar);
				}
			}

			// if a pre-defined parameter is changed to an inappropriate type
			if (event.getChangeType() == DtModelEvent.CHANGED_MODE) {

				String varName = eVar.getName();
				DtVariable dtVar = (DtVariable)eVar;

				if (varName.equals("Dimensions")) {
					dtVar.setMode(Variable.MODE_INPUT);
				}
				else if (varName.equals("Area") || varName.equals("Weight") || varName.equals("Volume")) {
					dtVar.setMode(Variable.MODE_OUTPUT);
				}
			}

		}


	}

	/**
	 * Validates the values of the properties
	 * @param validationList
	 * @throws SDKException
	 */
	public void validate(java.util.List validationList)
			throws SDKException {

		try {
			String name = myComponent.getName();
			MetaModel myMM = myComponent.getMetaModel();

			// warn if shape, material, or thickness are not specified
			if (shapeProp.getValueObj().getAsString().length() == 0) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_WARNING, myComponent,
						new IString(CLASS, 54510, "{0}: No shape specified for the plate", name), "shape"));
			}
			if (materialProp.getValueObj().getAsString().length() == 0) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_WARNING, myComponent,
						new IString(CLASS, 97233, "{0}: No material specified for the plate", name), "material"));
			}
			if (thicknessParam.getValueObj().getAsString().length() == 0) {
				validationList.add(new ValidationResult(ValidationEvent.SEVERITY_WARNING, myComponent,
						new IString(CLASS, 91096, "{0}: No thickness specified for the plate", name), "thickness"));
			}


		}
		catch (Exception e) {
			throw new SDKException(e, e.getMessage());
		}
	}

}
