//----------------------------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.willow.desktop;

import java.rmi.RemoteException;
import java.util.Map;

import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.WorkflowTransaction;
import org.huihoo.workflow.WorkflowUtilities;
import org.huihoo.workflow.desktop.CaseDatabase;
import org.huihoo.workflow.desktop.WorkflowImplementation;
import org.huihoo.workflow.event.WorkEvent;
import org.huihoo.workflow.event.WorkEventListener;
import org.huihoo.workflow.event.WorkflowEventUtilities;
import org.huihoo.workflow.server.WorkflowCase;
import org.huihoo.workflow.server.WorkflowDispatcher;
import org.huihoo.workflow.server.WorkflowWork;
import org.huihoo.workflow.server.WorkflowXPDL;
import org.huihoo.workflow.store.WorkflowWorkValidator;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowPackage;
import org.huihoo.workflow.xpdl.WorkflowProcess;

public class WorkflowDispatcherImpl implements WorkflowDispatcher
{
	protected WorkflowImplementation workflow;
	protected WorkflowXPDL workflowTemplate;

	public WorkflowDispatcherImpl(WorkflowImplementation workflow, WorkflowXPDL workflowTemplate)
		throws RemoteException
	{
		this.workflow = workflow;
		this.workflowTemplate = workflowTemplate;

	}

	public WorkflowImplementation getWorkflowImplementation()
	{
		return workflow;
	}

	//------------------------------------------------------------------------------------
	// WorkflowDispatcher core plain utilities   
	//------------------------------------------------------------------------------------                                        
	public boolean accept(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return accept(workflowprocess, workflowwork);
	}

	public boolean submit(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return submit(workflowprocess, workflowwork);
	}

	public boolean resubmit(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return resubmit(workflowprocess, workflowwork);
	}

	public boolean backtrack(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return backtrack(workflowprocess, workflowwork);
	}

	public boolean reverse(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return reverse(workflowprocess, workflowwork);
	}

	public boolean fetch(String workflowProcess, String workflowCase, String workflowWork)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return fetch(workflowprocess, workflowwork);
	}

	//如果用户显式的提供了分发的后继工作项的处理者的话，要求后继分发转移必须唯一
	//此接口属于高级功能，请遵循约束根据需要调用
	public boolean submit(String workflowProcess, String workflowCase, String workflowWork, Map userObject)
		throws WorkflowException, RemoteException
	{
		CaseDatabase casedatabase = workflow.getCaseDatabase();
		WorkflowPackage workflowpackage = workflow.getWorkflowPackage();
		WorkflowProcess workflowprocess = workflowpackage.findWorkflowProcess(workflowProcess);

		WorkflowCase workflowcase = casedatabase.findCase(workflowprocess, workflowCase);
		WorkflowWork workflowwork = casedatabase.findWork(workflowprocess, workflowcase, workflowWork);

		return submit(workflowprocess, workflowwork, userObject);
	}

	//------------------------------------------------------------------------------------
	// WorkflowDispatcher core utilities   
	//------------------------------------------------------------------------------------                                        
	public boolean accept(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkAccept(workflow.getDesktop().getSession(), workflowWork);
		}

		//------------------------------------------------------------
		//------------------------------------------------------------
		WorkflowActivity activity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.ACCEPTED);
		WorkEventListener[] listeners = activity.getWorkListeners();
		for (int i = 0; i < listeners.length; ++i)
		{
			listeners[i].enter(event);
		}

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().accept(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			for (int i = 0; i < listeners.length; ++i)
			{
				listeners[i].leave(event);
			}

		}
		catch (WorkflowException ex)
		{

			for (int i = 0; i < listeners.length; ++i)
			{
				listeners[i].notify(event, ex);
			}

			throw ex;
		}

		return resultBoolean;
	}

	public boolean submit(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkSubmit(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.SUBMITED);

		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().submit(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork,
						null);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);
		}
		catch (WorkflowException ex)
		{
			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);
			throw ex;
		}

		return resultBoolean;
	}

	public boolean resubmit(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkSubmit(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.SUBMITED);
		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().submit(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork,
						null);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);
		}
		catch (WorkflowException ex)
		{
			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);
			throw ex;
		}

		return resultBoolean;
	}

	public boolean backtrack(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkBacktrack(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.BACKTRACKED);
		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().backtrack(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);
		}
		catch (WorkflowException ex)
		{
			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);
			throw ex;
		}

		return resultBoolean;
	}

	public boolean reverse(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkReverse(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.BACKTRACKED);
		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().reverse(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);
		}
		catch (WorkflowException ex)
		{
			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);

			throw ex;
		}

		return resultBoolean;
	}

	public boolean fetch(WorkflowProcess workflowProcess, WorkflowWork workflowWork) throws WorkflowException
	{
		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkFetch(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.FETCHED);
		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().fetch(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);
		}
		catch (WorkflowException ex)
		{

			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);
			throw ex;
		}

		return resultBoolean;
	}

	//如果用户显式的提供了分发的后继工作项的处理者的话，要求后继分发转移必须唯一
	//此接口属于高级功能，请遵循约束根据需要调用
	public boolean submit(WorkflowProcess workflowProcess, WorkflowWork workflowWork, Map userObject)
		throws WorkflowException
	{

		WorkflowWorkValidator workValidator = workflowTemplate.getWorkflowTemplate().getWorkValidator();
		if (workValidator != null)
		{
			workValidator.checkSubmit(workflow.getDesktop().getSession(), workflowWork);
		}

		//	------------------------------------------------------------
		//	------------------------------------------------------------

		WorkflowActivity workflowActivity = workflowWork.getActivity();
		WorkEvent event = new WorkEvent(workflowWork, WorkEvent.SUBMITED);
		WorkflowEventUtilities.enterEvent(workflowActivity.getWorkListeners(), event);

		boolean resultBoolean = false;
		try
		{
			WorkflowTransaction transaction = null;
			try
			{
				transaction = workflowTemplate.getWorkflowTemplate().getCaseDatabase().getWorkflowTransaction();
				resultBoolean =
					workflowTemplate.getWorkflowTemplate().getWorkflowDispatcher().submit(
						workflow.getDesktop().getSession(),
						transaction,
						workflowProcess,
						workflowWork,
						userObject);
				transaction.commit();

			}
			catch (WorkflowException we)
			{
				WorkflowUtilities.rollbackNoThrow(transaction);
				throw we;
			}
			finally
			{
				WorkflowUtilities.releaseNoThrow(transaction);
			}

			WorkflowEventUtilities.leaveEvent(workflowActivity.getWorkListeners(), event);

		}
		catch (WorkflowException ex)
		{
			WorkflowEventUtilities.notifyEvent(workflowActivity.getWorkListeners(), event, ex);
			throw ex;
		}
		return resultBoolean;

	}
}
