package com.blueland.bpm.engine.core.listener;

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

import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.blueland.bpm.common.util.ApplicationContextHolder;
import com.blueland.bpm.engine.config.model.Depute;
import com.blueland.bpm.engine.config.service.DeputeManager;
import com.blueland.bpm.engine.core.model.ActivityReceiverModel;
import com.blueland.bpm.engine.core.model.ActivityResourceModel;
import com.blueland.bpm.engine.core.model.ExceptionErrorCode;
import com.blueland.bpm.engine.core.model.ProcessInputModel;
import com.blueland.bpm.engine.core.service.ProcessDefinitionService;
import com.blueland.bpm.engine.core.service.ProcessModelService;
import com.blueland.bpm.engine.util.ProcessDefinitionUtils;
import com.blueland.bpm.engine.util.ProcessModelUtils;
import com.blueland.bpm.engine.util.WorkFlowContants;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.blueland.bpm.identity.UserService;
import com.blueland.bpm.identity.model.User;

/**
 * 全局设置任务接收人监听器
 * 
 * @version: 1.0
 * @author lw
 */
public class GlobalTaskAssigneeListener implements TaskListener {
	private static final long serialVersionUID = 1L;
	private Logger logger = LoggerFactory.getLogger(getClass());
	private int MULTI_INSTANCE_USER_TASK = 2;
	private int MULTI_INSTANCE_CALL_ACTIVITY = 0;
	private int MULTI_INSTANCE_NOMAL = 1;

	@Override
	public void notify(DelegateTask delegate) {
		if (!delegate.getEventName().equals(TaskListener.EVENTNAME_CREATE))
			return;
		TaskEntity delegateTask = (TaskEntity) delegate;
		logger.debug("触发了全局监听器, pid={}, tid={}, event={}", new Object[] {
				delegateTask.getProcessInstanceId(), delegateTask.getId(),
				delegateTask.getEventName() });
		try {
			ProcessDefinitionEntity processDefinitionEntity = Context
					.getCommandContext()
					.getProcessDefinitionEntityManager()
					.findProcessDefinitionById(
							delegateTask.getProcessDefinitionId());
			// 获取客户端输入对象
			ProcessInputModel processInputModel = ProcessDefinitionUtils
					.getWfprocessInputModel(delegateTask);// 同步子流会返回数据
			logger.info("分配人员processInputModel对象,processInputModel={}", new Object[] {processInputModel});
			// 获取客户端接受人员列表
			String receiver = processInputModel.getWf_receiver();
			receiver = (receiver == null ? "" : receiver);
			int isMultiFlag = isMultiFlag(delegateTask, receiver);
			ActivityImpl prevTask = delegateTask.getExecution()
					.getProcessDefinition()
					.findActivity(delegateTask.getPreTaskDefKey());
			boolean isPrevTaskService=prevTask!=null&&BpmnXMLConstants.ELEMENT_TASK_SERVICE
					.equals(prevTask.getProperty("type"));
		/*	if(prevTask!=null&&BpmnXMLConstants.ELEMENT_TASK_SERVICE
					.equals(prevTask.getProperty("type"))){
				// 系统自动查找接受人
					receiver = getGroupFirstReceiver(
							delegateTask.getProcessInstanceId(),
							delegateTask.getProcessDefinitionId(),
							delegateTask.getId(), delegateTask.getPreTaskDefKey(),
							delegateTask.getTaskDefinitionKey(),
							delegateTask.getSender(), delegate.getVariables());
					if (StringUtils.isEmpty(receiver)) {
						throw new WorkFlowException(ExceptionErrorCode.B2064,"自动查询环节人员失败,delegate:"
								+ delegate);
					}
			}*/
			if ((StringUtils.isEmpty(receiver)
					&& isMultiFlag == MULTI_INSTANCE_NOMAL)||isPrevTaskService) {// 当客户端没有提交接受人且当前环节不是多实例任务时,自己找到环节绑定的资源
				// 系统自动查找接受人
				receiver = getGroupFirstReceiver(
						delegateTask.getProcessInstanceId(),
						delegateTask.getProcessDefinitionId(),
						delegateTask.getId(), delegateTask.getPreTaskDefKey(),
						delegateTask.getTaskDefinitionKey(),
						delegateTask.getSender(), delegate.getVariables());
				if (StringUtils.isEmpty(receiver)) {
					throw new WorkFlowException(ExceptionErrorCode.B2064,"自动查询环节人员失败,delegate:"
							+ delegate);
				}
			}
			// 规则1:普通用户任务设置人员逻辑
			if (isMultiFlag == MULTI_INSTANCE_NOMAL) {
				if(receiver.indexOf(',')!=-1)
					throw new WorkFlowException(ExceptionErrorCode.B2063,"error receiver["+receiver+"] count.");
				setAssignee(delegateTask, processInputModel,
						processDefinitionEntity.getKey(), receiver, MULTI_INSTANCE_NOMAL);
			} else if (isMultiFlag == MULTI_INSTANCE_CALL_ACTIVITY) {// 规则2:调用外部子流程-多实例任务设置人员逻辑
				ExecutionEntity executionEntity = delegateTask.getExecution()
						.getSuperExecution() != null ? delegateTask
						.getExecution().getSuperExecution() : delegateTask
						.getExecution();
				VariableInstanceEntity assigneeVar = (VariableInstanceEntity) executionEntity
						.getVariableInstances().get(
								WorkFlowContants.ELEMENT_ASSIGNEE);
				setSubBusinessKey(delegateTask.getExecution(),processInputModel,assigneeVar.getTextValue());
				setAssignee(delegateTask, processInputModel,
						processDefinitionEntity.getKey(),
						assigneeVar.getTextValue(), MULTI_INSTANCE_CALL_ACTIVITY);
			} else if (isMultiFlag == MULTI_INSTANCE_USER_TASK) {// 单环节多实例和内嵌子流程设置人员逻辑
				setAssignee(delegateTask, processInputModel,
						processDefinitionEntity.getKey(),
						delegateTask.getAssignee(), MULTI_INSTANCE_USER_TASK);
			}
			// 设置上下文
			setTaskVariables(delegateTask);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2061,"setAssignee error,delegate:"
					+ delegate, e);
		}
	}

	/**
	 * 分配接受人
	 * 
	 * @param delegateTask
	 * @param processInputModel
	 * @param procDefKey
	 * @param tempReceiver
	 * @param type
	 */
	private void setAssignee(TaskEntity delegateTask,
			ProcessInputModel processInputModel, String procDefKey,
			String tempReceiver, int type) {
		validateReceiver(tempReceiver);
		String receiver = existDeputeReplaceReceiver(procDefKey, tempReceiver,
				delegateTask.getTenantId(), delegateTask, processInputModel);
		if (type == MULTI_INSTANCE_CALL_ACTIVITY) {
			delegateTask.setAssignee(receiver, true, false);
			logger.info("执行子流程分配人员策略, receiver={}, curtActInstId={},curtActDefId={}, preActDefId={}", new Object[] {
					receiver, delegateTask.getId(),delegateTask.getTaskDefinitionKey(),delegateTask.getPreTaskDefKey()});
		} else if (type == MULTI_INSTANCE_NOMAL) {
			// 不记录IdentityLink的设置接受人
			delegateTask.setAssigneeNotRecordIdentityLink(receiver);
			logger.info("执行单环节分配人员策略, receiver={}, curtActInstId={},curtActDefId={}, preActDefId={}", new Object[] {
					receiver, delegateTask.getId(),delegateTask.getTaskDefinitionKey(),delegateTask.getPreTaskDefKey()});
		} else if (type == MULTI_INSTANCE_USER_TASK && !receiver.equals(tempReceiver)) {// 处理单环节多实例逻辑,有委托才会需要重新设置一次接受人
			delegateTask.setAssigneeNotRecordIdentityLink(receiver);
			logger.info("执行单环节多实例和内嵌子流程分配人员策略, receiver={}, curtActInstId={},curtActDefId={}, preActDefId={}", new Object[] {
					receiver, delegateTask.getId(),delegateTask.getTaskDefinitionKey(),delegateTask.getPreTaskDefKey()});
		}
	}

	/**
	 * 获取环节绑定资源的第一个资源值
	 * 
	 * @param procInstId
	 * @param proceDefId
	 * @param curtTaskId
	 * @param curtActDefId
	 * @param nextActDefId
	 * @param userId
	 * @param conditionMap
	 * @return
	 */
	public String getGroupFirstReceiver(String procInstId, String proceDefId,
			String curtTaskId, String curtActDefId, String nextActDefId,
			String userId, Map conditionMap) {
		ProcessDefinitionService processDefinitionService = (ProcessDefinitionService) ApplicationContextHolder
					.getBean("processDefinitionServiceImpl");
		UserService userService = (UserService) com.blueland.bpm.common.util.ApplicationContextHolder
				.getBean("userServiceImpl");
		com.blueland.bpm.identity.model.User user =null;
		if(userId!=null){
			user = userService
				.getUserById(userId);
		}else{
			user= new com.blueland.bpm.identity.model.User();
		}
		List<ActivityResourceModel> users = null;
		if (StringUtils.isEmpty(curtActDefId)) {
			users = processDefinitionService.getResource(proceDefId,
					nextActDefId);
		} else {
			users = processDefinitionService.getActivityUserTree(procInstId,
					proceDefId, curtTaskId, curtActDefId, nextActDefId,
					user.getUserCode(), user.getOrgId(), null, conditionMap);
		}
		String reicever="";
		for (ActivityResourceModel treeNode : users) {
			if ("USER".equals(treeNode.getType())) {
				reicever=  treeNode.getRealId();
				break;
			}
		}
		logger.info("执行自动查询人员策略, reicever={}, curtActDefId={}, nextActDefId={},curUserId={}", new Object[] {
				reicever, curtActDefId,nextActDefId,userId});
		return reicever;
	}

	/**
	 * 根据委托待办来转换receiver字段
	 * 
	 * @param processDefKey
	 * @param receiver
	 * @param appId
	 * @param delegateTask
	 * @param processInputModel
	 * @return
	 */
	public String existDeputeReplaceReceiver(String processDefKey,
			String receiver, String appId, TaskEntity delegateTask,
			ProcessInputModel processInputModel) {
		try {
			if (WorkFlowContants.ACTION_TYPE_LAUCH_PROCESS
					.equals(processInputModel.getWf_actionType())
					|| WorkFlowContants.ACTION_TYPE_LAUCH_SAVE_PROCESS
							.equals(processInputModel.getWf_actionType())) {
				// 如果接受人存在委托待办，就将被委托人替换成receiver,起草节点不进行委托处理
				boolean isStartUserTask = ProcessDefinitionUtils
						.isStartUserTask(delegateTask);
				if (isStartUserTask) {
					return receiver;
				}
			} else if (!(WorkFlowContants.ACTION_TYPE_EXECUTE_ACTIVITY
					.equals(processInputModel.getWf_actionType()) ||WorkFlowContants.ACTION_TYPE_CALLBACK_PREV_ACTIVITY
					.equals(processInputModel.getWf_actionType()) ||WorkFlowContants.ACTION_TYPE_CALLBACK_START_ACTIVITY
					.equals(processInputModel.getWf_actionType()) || WorkFlowContants.ACTION_TYPE_THROUGH_PROCESS
					.equals(processInputModel.getWf_actionType())|| WorkFlowContants.ACTION_TYPE_REJECT_ACTIVITY
					.equals(processInputModel.getWf_actionType())|| WorkFlowContants.ACTION_TYPE_ADD_MULTIINSTANCE_ACTIVITY
					.equals(processInputModel.getWf_actionType()))) {
				return receiver;
			}
			UserService userService = (UserService) com.blueland.bpm.common.util.ApplicationContextHolder
					.getBean("userServiceImpl");
			com.blueland.bpm.identity.model.User userReiver = userService
					.getUserById(receiver);
			DeputeManager deputeManager = (DeputeManager) ApplicationContextHolder
					.getBean("deputeManager");
			
			Depute depute = deputeManager.getUserProcessDepute(
					userReiver.getUserCode(), processDefKey, appId);
			//判断是否存在委托关系
			if (depute == null
					|| StringUtils.isEmpty(depute.getMandataryUserId())) {//不存在直接返回原始接受人
				return receiver;
			}
			if (userService.getUserById(depute.getMandataryUserId()) != null) {//委托人是否有效
				logger.info("执行委托代办逻辑, receiver={}, mandataryUserId={},curtActInstId={},curtActDefId={}, preActDefId={}", new Object[] {
						receiver,depute.getMandataryUserId(), delegateTask.getId(),delegateTask.getTaskDefinitionKey(),delegateTask.getPreTaskDefKey()});
				delegateTask.setOwner(receiver);//备份原始接受人
				return depute.getMandataryUserId();//返回委托人
			}
		} catch (Exception e) {
			this.logger.error("existDeputeReplaceReceiver error,processInputModel:"+processInputModel, e);
		}
		return receiver;

	}

	/**
	 * 设置任务上下文变量
	 * 
	 * @param delegateTask
	 */
	private void setTaskVariables(TaskEntity delegateTask) {
		Map<String, Object> taskVariables = delegateTask.getVariables() != null ? delegateTask
				.getVariables() : delegateTask.getExecution().getVariables();
		for (Map.Entry<String, Object> variable : taskVariables.entrySet()) {
			if (StringUtils.isEmpty(variable.getKey())
					|| variable.getValue() == null) {
				continue;
			}
			if (!(variable.getKey().equals(WorkFlowContants.WF_FIELDS_KEY)
					|| (variable.getKey()
							.equals(WorkFlowContants.WF_BUSINESS_DATA_OBJECT_KEY)) || (variable
						.getKey()
					.equals(WorkFlowContants.WF_PROCESS_INPUT_VARIABLE_KEY)))) {
				continue;
			}
			delegateTask.setVariableLocal(variable.getKey(),
					variable.getValue());
		}
	}

	private void validateReceiver(String receiver) {
		if (StringUtils.isEmpty(receiver) || "null".equals(receiver)
				|| "undefined".equals(receiver)) {
			throw new WorkFlowException(ExceptionErrorCode.B2062,"receiver的值为空或非法,receiver:" + receiver);
		}
	}

	private int isMultiFlag(TaskEntity delegateTask, String receiver) {
		boolean isCallActivityMultiInstance = false;
		boolean isSubProcessMultiInstance = false;
		//当通过流程管理重新分配人员,再执行下一步,再进行退回上一步时人员出错的逻辑判断
		if(WorkFlowContants.ACTION_TYPE_CALLBACK_PREV_ACTIVITY.equals(delegateTask.getActionType())&&StringUtils.isNotEmpty(receiver)){
			return MULTI_INSTANCE_NOMAL;
		}
		ActivityImpl curActivity = delegateTask.getExecution()
				.getProcessDefinition()
				.findActivity(delegateTask.getTaskDefinitionKey());
		// 获取是否单环节多人处理标记
		String multiInstance = (String) curActivity
				.getProperty(WorkFlowContants.ELEMENT_MULTIINSTANCE);
		if (StringUtils.isNotEmpty(multiInstance)) {
			return MULTI_INSTANCE_USER_TASK;
		}
		
		boolean isParallelGeteway = isGateway(delegateTask);
		// 调用外部子流程-多实例任务触发时,此时已是子流程的Execution,需要向上查找SuperExecution
		if (!isParallelGeteway
				&& delegateTask.getExecution().getSuperExecution() != null) {
			ExecutionEntity supperExecutionEntity = ((ExecutionEntity) delegateTask
					.getExecution().getSuperExecution());
			if (supperExecutionEntity != null) {
				isCallActivityMultiInstance = StringUtils
						.isNotEmpty((String) supperExecutionEntity
								.getActivity().getProperty(
										WorkFlowContants.ELEMENT_MULTIINSTANCE));
			}
			if (isCallActivityMultiInstance) {
				boolean isStartUserTask = ProcessDefinitionUtils
						.isStartUserTask(delegateTask);
				isCallActivityMultiInstance = isStartUserTask ? true : false;
			}
		} else if (delegateTask.getExecution().getParent() != null) {// 内部嵌套子流程多人处理
			ProcessModelService processModelService = (ProcessModelService) com.blueland.bpm.common.util.ApplicationContextHolder
					.getBean("processModelServiceImpl");
			ActivityImpl subActivity = delegateTask.getExecution().getParent()
					.getActivity();
			subActivity = subActivity == null ? delegateTask.getExecution()
					.getActivity().getParentActivity() : subActivity;
					if(subActivity!=null){
			boolean isSubProcess = BpmnXMLConstants.ELEMENT_SUBPROCESS
					.equals(subActivity.getProperty("type"));
			if (isSubProcess) {
				isSubProcessMultiInstance = StringUtils
						.isNotEmpty((String) subActivity
								.getProperty(WorkFlowContants.ELEMENT_MULTIINSTANCE))
						&& ProcessModelUtils.isSubProcessStartAct(
								processModelService
										.getBpmnModelByProcDefId(delegateTask
												.getProcessDefinitionId()),
								delegateTask.getTaskDefinitionKey()) != null;
			}
					}

		}
		if (isCallActivityMultiInstance) {
			return MULTI_INSTANCE_CALL_ACTIVITY;
		} else if (isSubProcessMultiInstance) {
			return MULTI_INSTANCE_USER_TASK;
		} else {
			return MULTI_INSTANCE_NOMAL;
		}

	}

	private boolean isGateway(TaskEntity delegateTask) {
		boolean isParallelGeteway = false;
		if (StringUtils.isNotEmpty(delegateTask.getPreTaskDefKey())) {
			ActivityImpl activityImpl = delegateTask.getExecution()
					.getProcessDefinition()
					.findActivity(delegateTask.getPreTaskDefKey());
			if (activityImpl != null) {
				isParallelGeteway = BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE
						.equals(activityImpl.getProperty("type"))
						|| BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL
								.equals(activityImpl.getProperty("type"));
			}
		}
		return isParallelGeteway;
	}
	
	private void setSubBusinessKey(ExecutionEntity executionEntity,
			ProcessInputModel processInputModel, String assignee) {
		try {
			List<ActivityReceiverModel> activityReceiverModels = processInputModel
					.getWf_receivers();
			if(activityReceiverModels==null||activityReceiverModels.isEmpty()){
				return;
			}
			UserService userService = (UserService) com.blueland.bpm.common.util.ApplicationContextHolder
					.getBean("userServiceImpl");
			User user=userService.getUserById(assignee);
			
			for (ActivityReceiverModel act : activityReceiverModels) {
				if (StringUtils.isNotEmpty(act.getSubBusinessKey())
						&& act.getReceiveUserId()
								.equals(user.getUserCode())
						&& act.getReceiveUserOrgId()
								.equals(user.getOrgId())) {
					executionEntity.setBusinessKey(act.getSubBusinessKey());
					Context.getCommandContext().getHistoryManager().updateProcessBusinessKeyInHistory(executionEntity);
					break;
				}
			}
		} catch (Exception e) {
			this.logger.error("为子流程设置subBusinessKey失败,executionEntity:"
					+ executionEntity + ",processInputModel:"
					+ processInputModel + ",assignee:" + assignee, e);
		}
	}

}