//----------------------------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.store;

import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.WorkflowTransaction;
import org.huihoo.workflow.WorkflowUtilities;
import org.huihoo.workflow.coreImpl.util.StringManager;
import org.huihoo.workflow.event.WorkEvent;
import org.huihoo.workflow.server.WorkflowCase;
import org.huihoo.workflow.server.WorkflowCaseContext;
import org.huihoo.workflow.server.WorkflowContext;
import org.huihoo.workflow.server.WorkflowSession;
import org.huihoo.workflow.server.WorkflowWork;
import org.huihoo.workflow.server.WorkflowXPDL;
import org.huihoo.workflow.store.WorkflowCaseDatabase;
import org.huihoo.workflow.usermodel.WorkflowParticipant;
import org.huihoo.workflow.util.WorkflowParticipantSelector;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowPackage;
import org.huihoo.workflow.xpdl.WorkflowProcess;
import org.huihoo.workflow.xpdl.WorkflowTransition;
import org.huihoo.workflow.xpdl.activity.ActivityType;
import org.huihoo.workflow.xpdl.activity.PerformerType;
import org.huihoo.workflow.xpdl.activity.SubFlowImplementation;

public class CommonDispatcher
{
	private static Log log = LogFactory.getLog("willow.CommonDispatcher");
	/**
	 * The string manager for this package.
	 */
	private static StringManager sm = StringManager.getManager(org.huihoo.workflow.coreImpl.store.Constants.PACKAGE);

	public static boolean submit_subflow(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{

		log.debug("workitem ==> " + workflowWork + " || transition ==> " + workflowTransition);
		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();
		WorkflowCase workflowCase = workflowWork.getCase();
		WorkflowPackage workflowPackage = workflowProcess.getWorkflowPackage();
		WorkflowActivity toActivity = workflowTransition.getToActivity();

		//1) create workflow workflowWork for subflow activity node
		String parentDispWorkId = null;
		WorkflowWork parentWork = workflowWork.getParentWork();

		parentDispWorkId =
			caseDatabase.createWork(
				workflowsession,
				userTransaction,
				workflowProcess,
				workflowCase,
				toActivity,
				parentWork,
				null,
				workflowWork.getDispatchTime(),
				WorkEvent.SUBMITED,
				WorkflowWork.DEFAULT_PRIORITY);

		WorkflowWork parentDispWork =
			caseDatabase.findWork(workflowsession, userTransaction, workflowProcess, workflowCase, parentDispWorkId);
		caseDatabase.createPath(
			workflowsession,
			userTransaction,
			workflowProcess,
			workflowCase,
			workflowWork,
			parentDispWork,
			pathDispatchBatch,
			WorkEvent.SUBMITED);

		//only accept ,not submit
		ControllerDispatcher.accept_core(
			workflowsession,
			workflowTemplate,
			userTransaction,
			workflowProcess,
			parentDispWork);

		//2) create workflow workflowWork for subflow process first activity node
		SubFlowImplementation impl = (SubFlowImplementation) toActivity.getImplementation();
		String suPprocessId = impl.getValue();
		WorkflowProcess subProcess = workflowPackage.findWorkflowProcess(suPprocessId);

		WorkflowActivity firstActivity = WorkflowUtilities.getInitialActivity(subProcess);

		//	-----------------------------------------------------------------
		//		试着找出工作项处理者
		//	 =======================================================
		//	 -----------------------------------------------------------------
		List participants =
			WorkflowParticipantSelector.select(
				workflowsession,
				workflowTemplate,
				workflowProcess,
				workflowWork,
				workflowTransition,
				userObject);

		//	 -----------------------------------------------------------------
		//	 -----------------------------------------------------------------
		if (participants == null || participants.size() == 0)
		{
			String childDispWorkId =
				caseDatabase.createWork(
					workflowsession,
					userTransaction,
					workflowProcess,
					workflowCase,
					firstActivity,
					parentDispWork,
					null,
					workflowWork.getDispatchTime(),
					WorkEvent.SUBMITED,
					WorkflowWork.DEFAULT_PRIORITY);

			WorkflowWork childDispWork =
				caseDatabase.findWork(workflowsession, userTransaction, workflowProcess, workflowCase, childDispWorkId);

			caseDatabase.createWorkEvent(
				workflowsession,
				userTransaction,
				workflowProcess,
				parentDispWork,
				workflowWork.getDispatchTime(),
				WorkEvent.ENTERSUBFLOW,
				childDispWorkId);

			return ControllerDispatcher.executeDispatchIfNecessary(
				workflowsession,
				workflowTemplate,
				userTransaction,
				workflowProcess,
				childDispWork,
				userObject);

		}
		else
		{
			int sizePerformer = participants.size();
			WorkflowParticipant performer = null;
			boolean dispath_OK = false;

			for (int i = 0; i < sizePerformer; ++i)
			{
				performer = (WorkflowParticipant) participants.get(i);
				String childDispWorkId =
					caseDatabase.createWork(
						workflowsession,
						userTransaction,
						workflowProcess,
						workflowCase,
						firstActivity,
						parentDispWork,
						performer,
						workflowWork.getDispatchTime(),
						WorkEvent.SUBMITED,
						WorkflowWork.DEFAULT_PRIORITY);

				WorkflowWork childDispWork =
					caseDatabase.findWork(workflowsession, userTransaction, workflowProcess, workflowCase, childDispWorkId);

				caseDatabase.createWorkEvent(
					workflowsession,
					userTransaction,
					workflowProcess,
					parentDispWork,
					workflowWork.getDispatchTime(),
					WorkEvent.ENTERSUBFLOW,
					childDispWorkId);

				dispath_OK =
					ControllerDispatcher.executeDispatchIfNecessary(
						workflowsession,
						workflowTemplate,
						userTransaction,
						workflowProcess,
						childDispWork,
						userObject);

				if (!dispath_OK)
				{
					break;
				}
			}

			return dispath_OK;
		}

	}

	//return parent process
	public static boolean submit_r2p(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{
		log.debug("workitem ==> " + workflowWork + " || transition ==> " + workflowTransition);
		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();
		WorkflowCase workflowCase = workflowWork.getCase();
		WorkflowWork parentWork = workflowWork.getParentWork();

		caseDatabase.createWorkEvent(
			workflowsession,
			userTransaction,
			workflowProcess,
			workflowWork,
			workflowWork.getDispatchTime(),
			WorkEvent.LEAVESUBFLOW,
			parentWork.getUUID());

		return ControllerDispatcher.dispatch_core(
			workflowsession,
			workflowTemplate,
			userTransaction,
			workflowProcess,
			parentWork,
			userObject);
	}

	public static boolean submit_general(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{
		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();

		PerformerType performerType = workflowTransition.getToActivity().getPerformerType();
		ActivityType activityType = workflowTransition.getToActivity().getActivityType();

		if (PerformerType.PERFORMER_AUTOMATION.equals(performerType)
			|| !ActivityType.ACTIVITY_BUSINESS.equals(activityType))
		{
			return submit_automation(
				workflowsession,
				workflowTemplate,
				userTransaction,
				workflowProcess,
				workflowWork,
				workflowTransition,
				pathDispatchBatch,
				userObject);
		}
		else
		{
			return submit_manual(
				workflowsession,
				workflowTemplate,
				userTransaction,
				workflowProcess,
				workflowWork,
				workflowTransition,
				pathDispatchBatch,
				userObject);
		}
	}

	private static boolean submit_automation(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{
		log.debug("workitem ==> " + workflowWork + " || transition ==> " + workflowTransition);

		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();
		WorkflowCase workflowCase = workflowWork.getCase();
		WorkflowActivity toActivity = workflowTransition.getToActivity();
		String autoDispWorkId = null;

		WorkflowWork parentWork = workflowWork.getParentWork();

		autoDispWorkId =
			caseDatabase.createWork(
				workflowsession,
				userTransaction,
				workflowProcess,
				workflowCase,
				toActivity,
				parentWork,
				null,
				workflowWork.getDispatchTime(),
				WorkEvent.SUBMITED,
				WorkflowWork.DEFAULT_PRIORITY);

		WorkflowWork autoDispWork =
			caseDatabase.findWork(workflowsession, userTransaction, workflowProcess, workflowCase, autoDispWorkId);

		caseDatabase.createPath(
			workflowsession,
			userTransaction,
			workflowProcess,
			workflowCase,
			workflowWork,
			autoDispWork,
			pathDispatchBatch,
			WorkEvent.SUBMITED);

		return ControllerDispatcher.executeDispatchIfNecessary(
			workflowsession,
			workflowTemplate,
			userTransaction,
			workflowProcess,
			autoDispWork,
			userObject);
	}

	private static boolean submit_manual(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{
		log.debug("workitem ==> " + workflowWork + " || transition ==> " + workflowTransition);
		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();
		WorkflowActivity workflowActivity = workflowTransition.getToActivity();
		PerformerType performerType = workflowActivity.getPerformerType();
		WorkflowCase workflowCase = workflowWork.getCase();
		WorkflowCaseContext caseContext = workflowCase.getCaseContext();

		//	-----------------------------------------------------------------
		//		试着找出工作项处理者
		//	 =======================================================
		//	 -----------------------------------------------------------------
		List participants =
			WorkflowParticipantSelector.select(
				workflowsession,
				workflowTemplate,
				workflowProcess,
				workflowWork,
				workflowTransition,
				userObject);

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

		if (participants == null || participants.size() == 0)
		{
			// how I can do? just log it
			WorkflowContext context = workflowTemplate.getWorkflowConfig().getWorkflowContext();
			String message =
				sm.getString("transition.notFound", workflowProcess.getWorkflowPackage(), workflowProcess, workflowActivity);
			context.log(message);

			throw new WorkflowException(message);
		}

		//log.debug("participant list: " + participants);

		int sizePerformer = participants.size();
		WorkflowParticipant performer = null;
		String targetWorkId = null;
		WorkflowWork targetWork = null;

		WorkflowWork parentWork = workflowWork.getParentWork();

		for (int i = 0; i < sizePerformer; ++i)
		{
			performer = (WorkflowParticipant) participants.get(i);
			targetWorkId =
				caseDatabase.createWork(
					workflowsession,
					userTransaction,
					workflowProcess,
					workflowCase,
					workflowActivity,
					parentWork,
					performer,
					workflowWork.getDispatchTime(),
					WorkEvent.SUBMITED,
					WorkflowWork.DEFAULT_PRIORITY);

			targetWork = caseDatabase.findWork(workflowsession, userTransaction, workflowProcess, workflowCase, targetWorkId);
			caseDatabase.createPath(
				workflowsession,
				userTransaction,
				workflowProcess,
				workflowCase,
				workflowWork,
				targetWork,
				pathDispatchBatch,
				WorkEvent.SUBMITED);
		}
		return true;
	}

	//end the workflow process
	public static boolean submit_endflow(
		WorkflowSession workflowsession,
		WorkflowXPDL workflowTemplate,
		WorkflowTransaction userTransaction,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		String pathDispatchBatch,
		Map userObject)
		throws WorkflowException
	{
		log.debug("workitem ==> " + workflowWork + " || transition ==> " + workflowTransition);

		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();

		WorkflowCase workflowCase = workflowWork.getCase();
		caseDatabase.createPath(
			workflowsession,
			userTransaction,
			workflowProcess,
			workflowCase,
			workflowWork,
			null,
			pathDispatchBatch,
			WorkEvent.SUBMITED);

		caseDatabase.completeCase(workflowsession, userTransaction, workflowProcess, workflowCase);

		return true;
	}
}
