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

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.selector.PerformerSelector;
import org.huihoo.workflow.server.WorkflowCase;
import org.huihoo.workflow.server.WorkflowCaseContext;
import org.huihoo.workflow.server.WorkflowWork;
import org.huihoo.workflow.server.WorkflowXPDL;
import org.huihoo.workflow.server.WorkflowSession;
import org.huihoo.workflow.store.Constants;
import org.huihoo.workflow.store.WorkflowCaseDatabase;
import org.huihoo.workflow.store.WorkflowUserDatabase;
import org.huihoo.workflow.usermodel.WorkflowDepartment;
import org.huihoo.workflow.usermodel.WorkflowGroup;
import org.huihoo.workflow.usermodel.WorkflowParticipant;
import org.huihoo.workflow.usermodel.WorkflowRole;
import org.huihoo.workflow.xpdl.ExtendedAttribute;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowProcess;
import org.huihoo.workflow.xpdl.WorkflowTransition;
import org.huihoo.workflow.xpdl.XPDLGlobals;
import org.huihoo.workflow.xpdl.activity.PerformerMode;
import org.huihoo.workflow.xpdl.activity.PerformerType;

public class WorkflowParticipantSelector
{
	public static List select(
		WorkflowSession workflowSession,
		WorkflowXPDL workflowTemplate,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition,
		Map userobject)
		throws WorkflowException
	{
		WorkflowCaseDatabase caseDatabase = workflowTemplate.getWorkflowTemplate().getCaseDatabase();
		WorkflowUserDatabase userDatabase = workflowTemplate.getWorkflowTemplate().getUserDatabase();

		WorkflowActivity workflowActivity = workflowTransition.getToActivity();
		PerformerType performerType = workflowActivity.getPerformerType();
		WorkflowCase workflowCase = workflowWork.getCase();
		WorkflowCaseContext caseContext = workflowCase.getCaseContext();

		List paricipant_id_list = Constants.getParticipants(userobject);

		List participants = null;
		List custom_paricipant_id_list = null;
		//---------------------------------------------------------
		//1. use customization participant list from sepcial dispatch
		//---------------------------------------------------------
		if (paricipant_id_list != null && paricipant_id_list.size() > 0)
		{
			custom_paricipant_id_list = paricipant_id_list;
		}
		//---------------------------------------------------------
		//2. use customization participant list from setByTransition
		//---------------------------------------------------------		
		if (custom_paricipant_id_list == null || custom_paricipant_id_list.size() == 0)
		{
			custom_paricipant_id_list = caseContext.getPerformersByTransition(workflowTransition);
		}

		//---------------------------------------------------------
		//3. use default participant list
		//---------------------------------------------------------	
		if (participants == null || participants.size() == 0)
		{
			participants =
				WorkflowParticipantSelector.select(
					workflowSession,
					userDatabase,
					workflowProcess,
					workflowWork,
					workflowTransition);
		}
		else
		{
			//validat participant?	
			if (!WorkflowParticipantChecker
				.check(workflowSession, workflowTemplate, workflowTransition.getToActivity(), custom_paricipant_id_list))
			{
				throw new WorkflowException("illegal participant list ");
			}

			participants = new ArrayList();
			int sizeUser = custom_paricipant_id_list.size();
			for (int i = 0; i < sizeUser; ++i)
			{
				participants.add(userDatabase.findParticipant(workflowSession, (String) custom_paricipant_id_list.get(i)));
			}
		}

		return participants;
	}

	public static List select(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowProcess workflowProcess,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition)
		throws WorkflowException
	{

		//System.err.println("------------>targetActivity : "+targetActivity);
		//限制只有 ActivityType.ACTIVITY_BUSINESS 是唯一的人机交互活动类型
		//if( ! ActivityType.ACTIVITY_BUSINESS.equals(targetActivity.getActivityType()))
		//{
		//	return null;
		//}

		WorkflowActivity targetActivity = workflowTransition.getToActivity();

		PerformerType performerType = targetActivity.getPerformerType();
		PerformerMode performerMode = targetActivity.getPerformerMode();

		if (PerformerType.PERFORMER_AUTOMATION.equals(performerType))
		{
			return null;
		}

		List users = null;

		if (PerformerType.PERFORMER_PARTICIPANT.equals(performerType))
		{
			users = WorkflowParticipantSelector.selectByParicipant(workflowSession, userDatabase, targetActivity);
		}
		else
			if (PerformerType.PERFORMER_GROUP.equals(performerType))
			{
				users = WorkflowParticipantSelector.selectByGroup(workflowSession, userDatabase, targetActivity);
			}
			else
				if (PerformerType.PERFORMER_ROLE.equals(performerType))
				{
					users = WorkflowParticipantSelector.selectByRole(workflowSession, userDatabase, targetActivity);
				}
				else
					if (PerformerType.PERFORMER_DEPARTMENT.equals(performerType))
					{
						users = WorkflowParticipantSelector.selectByDepartment(workflowSession, userDatabase, targetActivity);
					}
					else
						if (PerformerType.PERFORMER_CATEGORY.equals(performerType))
						{
							users = WorkflowParticipantSelector.selectByCategory(workflowSession, userDatabase, targetActivity);
						}
						else
							if (PerformerType.PERFORMER_RANK.equals(performerType))
							{
								users = WorkflowParticipantSelector.selectByRank(workflowSession, userDatabase, targetActivity);
							}
							else
								if (PerformerType.PERFORMER_SELECTOR.equals(performerType))
								{
									users =
										WorkflowParticipantSelector.selectBySelector(workflowSession, workflowWork, workflowTransition);
								}

		if ((users == null) || (users.size() == 0))
		{
			throw new WorkflowException("participant must be provided for " + targetActivity);
		}

		if (PerformerMode.SINGLE_SELECTION.equals(performerMode) && users.size() > 1)
		{
			throw new WorkflowException("participant count is greater than one when mode is SINGLE_SELECTION");
		}

		return users;
	}

	//------------------------------------------------------------------------------
	//	private function blocks
	//------------------------------------------------------------------------------
	private static List selectByParicipant(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		//System.err.println("------------------------------------------------------");
		List users = new ArrayList();
		List userIds = targetActivity.getPerformers();

		int sizeUser = userIds.size();
		for (int i = 0; i < sizeUser; ++i)
		{
			//System.err.println("---->"+(String) userIds.get(i));
			appendToUserList(users, userDatabase.findParticipant(workflowSession, (String) userIds.get(i)));
		}
		return users;
	}

	private static List selectByGroup(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		List users = new ArrayList();
		List groupIds = targetActivity.getPerformers();
		int sizeGroup = groupIds.size();
		for (int i = 0; i < sizeGroup; ++i)
		{
			WorkflowGroup group = (WorkflowGroup) userDatabase.findGroup(workflowSession, (String) groupIds.get(i));
			Iterator userInterator = group.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				appendToUserList(users, user);
			}
		}
		return users;
	}

	private static List selectByRole(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		List users = new ArrayList();
		List roleIds = targetActivity.getPerformers();
		int sizeRole = roleIds.size();
		for (int i = 0; i < sizeRole; ++i)
		{
			WorkflowRole role = (WorkflowRole) userDatabase.findRole(workflowSession, (String) roleIds.get(i));
			Iterator userInterator = role.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				appendToUserList(users, user);
			}
		}
		return users;
	}

	private static List selectByDepartment(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		List users = new ArrayList();
		List deptIds = targetActivity.getPerformers();
		int sizeDept = deptIds.size();
		for (int i = 0; i < sizeDept; ++i)
		{
			WorkflowDepartment dept =
				(WorkflowDepartment) userDatabase.findDepartment(workflowSession, (String) deptIds.get(i));
			Iterator userInterator = dept.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				appendToUserList(users, user);
			}
		}
		return users;
	}

	private static List selectByCategory(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		List users = new ArrayList();
		List catIds = targetActivity.getPerformers();
		int sizeCat = catIds.size();
		for (int i = 0; i < sizeCat; ++i)
		{
			String catId = (String) catIds.get(i);
			Iterator depts = userDatabase.getDepartments(workflowSession);
			while (depts.hasNext())
			{
				WorkflowDepartment dept =
					(WorkflowDepartment) userDatabase.findDepartment(workflowSession, (String) depts.next());

				if (dept.getCategory() != null && catId.equals(dept.getCategory().getUUID()))
				{
					Iterator userInterator = dept.getParticipants();
					while (userInterator.hasNext())
					{
						WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
						appendToUserList(users, user);
					}
				}
			}
		}
		return users;
	}

	private static List selectByRank(
		WorkflowSession workflowSession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity)
		throws WorkflowException
	{
		List users = new ArrayList();
		List rankIds = targetActivity.getPerformers();
		int sizeRank = rankIds.size();
		for (int i = 0; i < sizeRank; ++i)
		{
			String rankId = (String) rankIds.get(i);
			Iterator userInterator = userDatabase.getParticipants(workflowSession);
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				if (user.getRank() != null && rankId.equals(user.getRank().getUUID()))
				{
					appendToUserList(users, user);
				}
			}
		}
		return users;
	}

	private static List selectBySelector(
		WorkflowSession workflowSession,
		WorkflowWork workflowWork,
		WorkflowTransition workflowTransition)
		throws WorkflowException
	{
		List users = new ArrayList();
		WorkflowActivity targetActivity = workflowTransition.getToActivity();
		ExtendedAttribute attribute =
			(ExtendedAttribute) targetActivity.getExtendedAttributes().get(
				XPDLGlobals.PERFORMER_SELECTOR_QUALIFIED_CLASS_NAME);

		String implClassName = attribute.getValue();
		Class implClass = null;
		PerformerSelector selector = null;
		try
		{
			implClass = Class.forName(implClassName);
			selector = (PerformerSelector) implClass.newInstance();
		}
		catch (Exception e)
		{
			WorkflowException ex = new WorkflowException("can not select participants");
			ex.setRootCause(e);
			throw ex;
		}

		users = selector.select(workflowWork, workflowTransition);

		return users;
	}

	private static void appendToUserList(List users, WorkflowParticipant user)
	{
		int sizeUsers = users.size();
		boolean found = false;
		WorkflowParticipant temp = null;
		for (int i = 0; i < sizeUsers; ++i)
		{
			temp = (WorkflowParticipant) users.get(i);
			if (user.getUUID().equals(temp.getUUID()))
			{
				found = true;
				break;
			}
		}
		if (!found)
		{
			users.add(user);
		}
	}
}
