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

import java.util.ArrayList;
import java.util.List;

import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.HistoricProcessInstanceQueryImpl;
import org.activiti.engine.impl.ProcessInstanceQueryImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
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.runtime.Execution;
import org.apache.commons.lang3.StringUtils;

import com.blueland.bpm.engine.util.WorkFlowContants;

/**
 * 流程作废命令类
 * @author lw
 */
public class CancelProcessInstanceCmd implements Command<Void>{
	protected final String executionId;
	protected final String taskId;
	protected final String reason;
	
	public CancelProcessInstanceCmd(String executionId, String taskId,String reason) {
		this.executionId = executionId;
		this.taskId = taskId;
		this.reason=reason;
	}

	public Void execute(CommandContext commandContext) {
		TaskEntity task = null;
		if(taskId!=null){
			task = commandContext.getTaskEntityManager().findTaskById(taskId);
		}else{
			task=new TaskEntity();
		}
		ExecutionEntity curExecutionEntity = commandContext.getExecutionEntityManager().findExecutionById(executionId);
		ProcessDefinitionEntity processDefinition = commandContext.getProcessDefinitionEntityManager().findProcessDefinitionById(curExecutionEntity.getProcessDefinitionId());
		commandContext.getHistoryManager().recordProcessInstanceCancel(executionId, reason, task.getTaskDefinitionKey());
		// All child executions are suspended
		List<ExecutionEntity> childExecutions=new ArrayList<ExecutionEntity>();
		String topExecutionId="";
		if(StringUtils.isNotEmpty(curExecutionEntity.getSuperExecutionId())){
			topExecutionId=curExecutionEntity.getTopProcessInstanceId();
			List<ExecutionEntity> executions=getAllExecutionEntity(topExecutionId,commandContext);
			childExecutions.addAll(executions);
		}else{
			childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByProcessInstanceId(executionId);
			topExecutionId=curExecutionEntity.getProcessInstanceId();
		}
		
	    for (ExecutionEntity childExecution : childExecutions) {
	      if (!childExecution.getId().equals(executionId)) {
	    	  commandContext.getHistoryManager().recordProcessInstanceCancel(childExecution.getId(), reason, task.getTaskDefinitionKey());
	      }
	    }
		// All tasks are suspended
	    List<HistoricProcessInstance> procInsts=getAllProcessInstance(topExecutionId,commandContext);
	    for (HistoricProcessInstance historicProcessInstance : procInsts) {
	    	 List<TaskEntity> tasks = commandContext.getTaskEntityManager()
	 				.findTasksByProcessInstanceId(historicProcessInstance.getId());
	 		for (TaskEntity taskEntity : tasks) {
	 			if(taskId!=null&&taskId.equals(taskEntity.getId())){
	 				taskEntity.setActionType(WorkFlowContants.ACTION_TYPE_CANCEL_PROCESS);
	 				commandContext.getHistoryManager().recordTaskUpdate(taskEntity);
	 			}
	 			taskEntity.setDescription(WorkFlowContants.ACTION_TYPE_CANCEL_PROCESS);
	 			commandContext.getTaskEntityManager().deleteTaskForce(taskEntity.getId(), reason, false);
	 		}
		}
		curExecutionEntity.setProcessDefinition(processDefinition);
 		task.setProcessInstance(curExecutionEntity);
 		Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
 		          ActivitiEventBuilder.createEntityEvent(ActivitiEventType.PROCESS_CANCEL, curExecutionEntity));
		return null;
	}
	
	
	/**
	 * 找到所有流程列表（找子）
	 * @param topExecutionId
	 * @param commandContext
	 * @return
	 */
	public List<HistoricProcessInstance> getAllProcessInstance(
			String topExecutionId, CommandContext commandContext) {
		HistoricProcessInstanceQueryImpl query = new HistoricProcessInstanceQueryImpl();
		query.processInstanceId(topExecutionId);
		List<HistoricProcessInstance> historicProcessInstances =commandContext.getHistoricProcessInstanceEntityManager().getAllProcessInstance(query);
		return historicProcessInstances;
	}

	
	public List<ExecutionEntity> getAllExecutionEntity(String topExecutionId,CommandContext commandContext){
		ProcessInstanceQueryImpl query = new ProcessInstanceQueryImpl();
		query.processInstanceId(topExecutionId);
		List<ExecutionEntity> executions = commandContext.getExecutionEntityManager().findAllExecution(query);
		List<ExecutionEntity> executionEntitys=new ArrayList<ExecutionEntity>();
		for (Execution execution : executions) {
			executionEntitys.add((ExecutionEntity) execution);
		}
		return executionEntitys;
	}

}
