//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/willow
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : willow@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.workflow.coreImpl.xpdl.parser.xmlrules;
import java.beans.PropertyDescriptor;
import java.util.HashMap;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.digester.Rule;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowProcess;
import org.huihoo.workflow.xpdl.WorkflowTransition;
import org.xml.sax.Attributes;

public class SetTransitionActivityRule extends Rule
{
	//----------------------------------------------------------- Constructors
	/**
	 * Construct a "set property" rule with the specified name and value
	 * attributes.
	 *
	 * @param digester The digester with which this rule is associated
	 * @param name Name of the property 
	 * @param value Name of the attribute that will contain the value to which
	 *        the property should be set
	 */
	public SetTransitionActivityRule(String propName, String xmlName)
	{
		this.propName = propName;
		this.xmlName = xmlName;
	}
	// ----------------------------------------------------- Instance Variables
	/**
	 * The attribute that will contain the property name.
	 */
	protected String propName = null;
	/**
	 * The attribute that will contain the property value.
	 */
	protected String xmlName = null;

	// Build a set of attribute names and corresponding values
	protected HashMap values = new HashMap();

	// --------------------------------------------------------- Public Methods
	/**
	 * This method is called when the beginning of a matching XML element
	 * is encountered. The default implementation delegates to the deprecated
	 * method {@link #begin(Attributes) begin} without the 
	 * <code>namespace</code> and <code>name</code> parameters, to retain 
	 * backwards compatibility.
	 *
	 * @param namespace the namespace URI of the matching element, or an 
	 *   empty string if the parser is not namespace aware or the element has
	 *   no namespace
	 * @param eleName the local name if the parser is namespace aware, or just 
	 *   the element name otherwise
	 * @param attributes The attribute list of this element
	 * @since Digester 1.4
	 */
	public void begin(String namespace, String eleNname, Attributes attributes) throws Exception
	{
		//System.err.println("-------begin---------SetTransitionActivityRule------------");

		for (int i = 0; i < attributes.getLength(); i++)
		{
			String name = attributes.getLocalName(i);
			if ("".equals(name))
			{
				name = attributes.getQName(i);
			}
			String value = attributes.getValue(i);

			if (name != null)
			{
				values.put(name, value);
			}
		}
	}

	/**
	 * This method is called when the end of a matching XML element
	 * is encountered. The default implementation delegates to the deprecated
	 * method {@link #end end} without the 
	 * <code>namespace</code> and <code>name</code> parameters, to retain 
	 * backwards compatibility.
	 *
	 * @param namespace the namespace URI of the matching element, or an 
	 *   empty string if the parser is not namespace aware or the element has
	 *   no namespace
	 * @param name the local name if the parser is namespace aware, or just 
	 *   the element name otherwise
	 * @since Digester 1.4
	 */
	public void end(String namespace, String name) throws Exception
	{
		//System.err.println("-------end---------SetTransitionActivityRule------------");

		// Identify the actual property name and value to be used
		String actualName = this.propName;
		String actualValueId = null;
		WorkflowActivity activity = null;
		actualValueId=(String)values.get(this.xmlName);
	
		// Get a reference to the top object
		Object top = digester.peek();
		// Log some debugging information
		if (digester.getLogger().isDebugEnabled())
		{
			digester.getLogger().debug(
				"[SetTransitionActivityRule]{"
					+ digester.getMatch()
					+ "} Set "
					+ top.getClass().getName()
					+ " property "
					+ actualName
					+ " to "
					+ actualValueId);
		}
//		System.err.println(
//			"[SetTransitionActivityRule]{"
//				+ digester.getMatch()
//				+ "} Set "
//				+ top.getClass().getName()
//				+ " property "
//				+ actualName
//				+ " to "
//				+ actualValueId);

		// Force an exception if the property does not exist
		// (BeanUtils.setProperty() silently returns in this case)
		if (top instanceof DynaBean)
		{
			DynaProperty desc = ((DynaBean) top).getDynaClass().getDynaProperty(actualName);
			if (desc == null)
			{
				throw new NoSuchMethodException("Bean has no property named " + actualName);
			}
		}
		else /* this is a standard JavaBean */ {
			PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(top, actualName);
			if (desc == null)
			{
				throw new NoSuchMethodException("Bean has no property named " + actualName);
			}
		}
		// Set the property (with conversion as necessary)
		WorkflowTransition target = (WorkflowTransition) top;
		//System.err.println("[target] " + target);

		if (actualValueId != null && actualValueId.length() > 0)
		{
			//System.err.println("[SetTransitionActivityRule]----------------------- ");
			WorkflowProcess workflowPocess = target.getWorkflowProcess();
			//System.err.println("[Process] "+workflowPocess);

			activity = workflowPocess.findActivity(actualValueId);
		//	System.err.println("[WorkflowTransition] Id=" + target.getUUID() + ",activity=" + actualName);
		//	System.err.println("[WorkflowActivity] activity=" + activity + ",Id=" + actualValueId);
		}

		BeanUtils.setProperty(target, actualName, activity);

	}

	/**
	 * Render a printable version of this Rule.
	 */
	public String toString()
	{
		StringBuffer sb = new StringBuffer("SetTransitionActivityRule[");
		sb.append("propName=");
		sb.append(propName);
		sb.append(", xmlName=");
		sb.append(xmlName);
		sb.append("]");
		return (sb.toString());
	}
}
