//----------------------------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.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.desktop.UserDatabase;
import org.huihoo.workflow.desktop.WorkflowImplementation;
import org.huihoo.workflow.server.WorkflowXPDL;
import org.huihoo.workflow.server.WorkflowSession;
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.WorkflowActivity;
import org.huihoo.workflow.xpdl.activity.PerformerMode;
import org.huihoo.workflow.xpdl.activity.PerformerType;

public class WorkflowParticipantChecker
{
	public static boolean check(
	  WorkflowSession workflowsession,
		WorkflowXPDL workflowtemplate,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		WorkflowUserDatabase userDatabase = workflowtemplate.getWorkflowTemplate().getUserDatabase();

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

		if (paricipant_id_list == null || paricipant_id_list.size() == 0)
		{
			return false;
		}

		if (PerformerMode.SINGLE_SELECTION.equals(performerMode) && paricipant_id_list.size() > 1)
		{
			return false;
		}

		if (PerformerType.PERFORMER_PARTICIPANT.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByParicipant(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_GROUP.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByGroup(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_ROLE.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByRole(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_DEPARTMENT.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByDepartment(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_CATEGORY.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByCategory(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_RANK.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByRank(workflowsession,userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_SELECTOR.equals(performerType))
		{
			return true;
		}

		return false;
	}

	//------------------------------------------------------------------------------
	//	private function blocks
	//------------------------------------------------------------------------------
	private static boolean checkByParicipant(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = targetActivity.getPerformers();
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByGroup(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = 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();
				userIds.add(user.getUUID());
			}
		}

		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByRole(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = 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();
				userIds.add(user.getUUID());
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByDepartment(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = 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();
				userIds.add(user.getUUID());
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByCategory(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = 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();
						userIds.add(user.getUUID());
					}
				}
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByRank(WorkflowSession workflowsession,
		WorkflowUserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = 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()))
				{
					userIds.add(user.getUUID());
				}
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	public static boolean check(
		WorkflowImplementation workflow,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		UserDatabase userDatabase = workflow.getUserDatabase();

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

		if (paricipant_id_list == null || paricipant_id_list.size() == 0)
		{
			return false;
		}

		if (PerformerMode.SINGLE_SELECTION.equals(performerMode) && paricipant_id_list.size() > 1)
		{
			return false;
		}

		if (PerformerType.PERFORMER_PARTICIPANT.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByParicipant(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_GROUP.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByGroup(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_ROLE.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByRole(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_DEPARTMENT.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByDepartment(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_CATEGORY.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByCategory(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_RANK.equals(performerType))
		{
			return WorkflowParticipantChecker.checkByRank(userDatabase, targetActivity, paricipant_id_list);
		}
		else if (PerformerType.PERFORMER_SELECTOR.equals(performerType))
		{
			return true;
		}

		return false;
	}

	//------------------------------------------------------------------------------
	//	private function blocks
	//------------------------------------------------------------------------------
	private static boolean checkByParicipant(
		UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException
	{
		List userIds = targetActivity.getPerformers();
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByGroup(UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		List userIds = new ArrayList();
		List groupIds = targetActivity.getPerformers();
		int sizeGroup = groupIds.size();
		for (int i = 0; i < sizeGroup; ++i)
		{
			WorkflowGroup group = (WorkflowGroup) userDatabase.findGroup((String) groupIds.get(i));
			Iterator userInterator = group.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				userIds.add(user.getUUID());
			}
		}

		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByRole(UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		List userIds = new ArrayList();
		List roleIds = targetActivity.getPerformers();
		int sizeRole = roleIds.size();
		for (int i = 0; i < sizeRole; ++i)
		{
			WorkflowRole role = (WorkflowRole) userDatabase.findRole((String) roleIds.get(i));
			Iterator userInterator = role.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				userIds.add(user.getUUID());
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByDepartment(UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		List userIds = new ArrayList();
		List deptIds = targetActivity.getPerformers();
		int sizeDept = deptIds.size();
		for (int i = 0; i < sizeDept; ++i)
		{
			WorkflowDepartment dept = (WorkflowDepartment) userDatabase.findDepartment((String) deptIds.get(i));
			Iterator userInterator = dept.getParticipants();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				userIds.add(user.getUUID());
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByCategory(UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		List userIds = 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();
			while (depts.hasNext())
			{
				WorkflowDepartment dept = (WorkflowDepartment) userDatabase.findDepartment((String) depts.next());

				if (dept.getCategory() != null && catId.equals(dept.getCategory().getUUID()))
				{
					Iterator userInterator = dept.getParticipants();
					while (userInterator.hasNext())
					{
						WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
						userIds.add(user.getUUID());
					}
				}
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}

	private static boolean checkByRank(UserDatabase userDatabase,
		WorkflowActivity targetActivity,
		List paricipant_id_list)
		throws WorkflowException,RemoteException
	{
		List userIds = 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();
			while (userInterator.hasNext())
			{
				WorkflowParticipant user = (WorkflowParticipant) userInterator.next();
				if (user.getRank() != null && rankId.equals(user.getRank().getUUID()))
				{
					userIds.add(user.getUUID());
				}
			}
		}
		return userIds.containsAll(paricipant_id_list);
	}
}
