//----------------------------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.xpdl.activity;
import java.util.ArrayList;
import java.util.List;

import org.huihoo.workflow.InvocationException;
import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.server.WorkflowCase;
import org.huihoo.workflow.server.WorkflowWork;
import org.huihoo.workflow.util.UUID;
import org.huihoo.workflow.xpdl.WorkflowApplication;
import org.huihoo.workflow.xpdl.WorkflowInvocation;
import org.huihoo.workflow.xpdl.WorkflowPackage;
import org.huihoo.workflow.xpdl.WorkflowParameter;
import org.huihoo.workflow.xpdl.parameter.ActualParameter;
import org.huihoo.workflow.xpdl.parameter.FormalParameter;
import org.huihoo.workflow.xpdl.parameter.ParameterMode;

public class ToolImplementation extends Implementation
{
	// added serialver computed by the tool
	//private static final long serialVersionUID = 612469292430209212L;

	private List parameters = new ArrayList();
	private String applicationID;

	public ToolImplementation()
	{
		this(null);
	}

	public ToolImplementation(String appID)
	{
		this.setValue(appID);
		this.uuid = new UUID().toString();
	}

	public void execute(WorkflowWork workItem, ClassLoader loader) throws InvocationException,WorkflowException
	{
		if (loader == null)
		{
			loader = ToolImplementation.class.getClassLoader();
		}

		Class implClass = null;
		
		try
		{
			WorkflowCase workflowCase = workItem.getCase();
			WorkflowPackage pkg = workflowCase.getWorkflowProcess().getWorkflowPackage();
			WorkflowApplication app = pkg.findApplication(getValue());
			String implClassName = app.getQualifiedClassName();
			
			if (loader != null)
			{
					implClass = loader.loadClass(implClassName);
	
			}
			else
			{
					implClass = Class.forName(implClassName);

			}

			WorkflowInvocation call = (WorkflowInvocation) implClass.newInstance();
			call.invoke(workItem, makeParamerers(workflowCase, app));
		}
		catch (Exception ex)
		{
			if(ex instanceof WorkflowException)
			{
				throw (WorkflowException)ex;
			}
			else
			{
				WorkflowException ne=new WorkflowException();
				ne.setRootCause(ex);
			
				throw ne;			
			}
		}
	}
	public List getActualParameters()
	{
		return parameters;
	}
	public void addActualParameter(ActualParameter parameter)
	{
		if (parameter != null && findActualParameter(parameter.getUUID()) == null)
		{
			parameters.add(parameter);
		}
	}
	public ActualParameter findActualParameter(String id)
	{
		int sizeParams = parameters.size();
		ActualParameter result = null;

		for (int i = 0; i < sizeParams; ++i)
		{
			result = (ActualParameter) parameters.get(i);

			if (result.getUUID().equals(id))
			{
				return result;
			}

		}
		return result;
	}

	public String getValue()
	{
		return applicationID;
	}
	public void setValue(String applicationId)
	{
		this.applicationID = applicationId;
	}

	//---------------------private blocks
	private WorkflowParameter[] makeParamerers(WorkflowCase workflowCase, WorkflowApplication app)
		throws CloneNotSupportedException
	{
		WorkflowParameter[] params = null;

		FormalParameter formalParameter = null;
		WorkflowParameter initParameter = null;
		ActualParameter actualParameter = null;

		ParameterMode paramMode = null;
		Class srcClass = null;
		Class dstClass = null;

		int sizeParams = app.getFormalParameters().size();

		params = new WorkflowParameter[sizeParams];

		for (int i = 0; i < sizeParams; ++i)
		{
			formalParameter = app.findFormalParameter(i);
			actualParameter = (ActualParameter) parameters.get(i);

			int acp_type = actualParameter.getType();
			if (acp_type == ActualParameter.CONSTANT_PARAMETER)
			{
				initParameter = new WorkflowParameter("CONSTANT", "CONSTANT", formalParameter.getType());
				initParameter.setValue(actualParameter.getValue());
			}
			else if (acp_type == ActualParameter.WORKFLOW_PARAMETER)
			{
				initParameter = workflowCase.getCaseContext().getParameterByName(actualParameter.getValue());
			}
			else
			{
				initParameter = workflowCase.getCaseContext().getParameterByName(actualParameter.getValue());
				if (initParameter != null)
				{
					actualParameter.setType(ActualParameter.WORKFLOW_PARAMETER);
				}
				else
				{
					actualParameter.setType(ActualParameter.CONSTANT_PARAMETER);
					initParameter = new WorkflowParameter("CONSTANT", "CONSTANT", formalParameter.getType());
					initParameter.setValue(actualParameter.getValue());
				}
			}

			srcClass = formalParameter.getType();
			dstClass = initParameter.getType();
			paramMode = formalParameter.getMode();

			if (dstClass.equals(srcClass))
			{
				if (paramMode.equals(ParameterMode.MODE_IN))
				{
					params[i] = initParameter.copy();
				}
				else
				{
					params[i] = initParameter;
				}
			}
			else
			{
				//type check failed
				throw new java.lang.IllegalArgumentException();
			}
		}

		return params;
	}

	public String getTagName()
	{
		return "Tool";
	}
}
