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

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

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.blueland.bpm.common.util.StringUtils;
import com.blueland.bpm.engine.core.handler.BizProcessHandler;
import com.blueland.bpm.engine.core.model.ExceptionErrorCode;
import com.blueland.bpm.engine.core.model.ProcessInputModel;
import com.blueland.bpm.engine.core.model.ProcessInstanceModel;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.blueland.bpm.log.model.ProcessErrorLog;

/**
 * 获取Activiti5相关Service的辅助类
 * @version:  1.0
 * @author lw 
 */
@Service
public class AbstractServiceHelper implements  ActivitiService{
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	protected RepositoryService repositoryService;
	@Autowired
	protected RuntimeService runtimeService;
	@Autowired
	protected HistoryService historyService;
	@Autowired
	protected IdentityService identityService;
	@Autowired
	protected TaskService taskService;
	@Autowired
	protected FormService formService;
	@Autowired
	protected ManagementService managementService;
	@Autowired
	protected ProcessEngineConfiguration processEngineConfiguration;
	@Autowired
	protected BizProcessHandlerFactory bussinessProcessHandlerFactory;
	public RepositoryService getRepositoryService() {
		return repositoryService;
	}

	public void setRepositoryService(RepositoryService repositoryService) {
		this.repositoryService = repositoryService;
	}

	public RuntimeService getRuntimeService() {
		return runtimeService;
	}

	public void setRuntimeService(RuntimeService runtimeService) {
		this.runtimeService = runtimeService;
	}

	public HistoryService getHistoryService() {
		return historyService;
	}

	public void setHistoryService(HistoryService historyService) {
		this.historyService = historyService;
	}

	public IdentityService getIdentityService() {
		return identityService;
	}

	public void setIdentityService(IdentityService identityService) {
		this.identityService = identityService;
	}

	public TaskService getTaskService() {
		return taskService;
	}

	public void setTaskService(TaskService taskService) {
		this.taskService = taskService;
	}

	public FormService getFormService() {
		return formService;
	}

	public void setFormService(FormService formService) {
		this.formService = formService;
	}

	public ManagementService getManagementService() {
		return managementService;
	}

	public void setManagementService(ManagementService managementService) {
		this.managementService = managementService;
	}

	public ProcessEngineConfiguration getProcessEngineConfiguration() {
		return processEngineConfiguration;
	}

	public void setProcessEngineConfiguration(
			ProcessEngineConfiguration processEngineConfiguration) {
		this.processEngineConfiguration = processEngineConfiguration;
	}
	
	public BizProcessHandler getBussinessProcessHandler(String processDefinitionId){
		BizProcessHandler handler=null;
		try{
			handler=bussinessProcessHandlerFactory.buildBussinessProcessHandler(processDefinitionId);
		}catch(Exception e){
			logger.error("", e);
		}
		return handler;
	}
	

	/**
	 * 根据流程定义ID获取流程定义对象
	 * @param procDefId
	 * @return
	 */
	public ProcessDefinition getProcessDefinition(String procDefId)  {
		if(procDefId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"procDefId is null");
		}
		ProcessDefinition processDefinition=null;
		try{
			processDefinition=this.repositoryService.getProcessDefinition(procDefId);
		}catch(Exception e){
			throw new WorkFlowException(ExceptionErrorCode.B2002,"当前流程定义未找到!procDefId:"+procDefId,e);
		}
		if (processDefinition == null) {
			throw new WorkFlowException(ExceptionErrorCode.B2002,"当前流程定义未找到!procDefId:"+procDefId);
		}
		return processDefinition;
	}


	/**
	 * 根据流程定义ID获取流程定义对象
	 * @param procDefId
	 * @return
	 */
	public ReadOnlyProcessDefinition getDeployedProcessDefinition(String procDefId)  {
		if(procDefId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"procDefId is null");
		}
		RepositoryServiceImpl repositoryServiceImpl = (org.activiti.engine.impl.RepositoryServiceImpl) repositoryService;
		ReadOnlyProcessDefinition rpd=null;
		try{
			rpd = repositoryServiceImpl
				.getDeployedProcessDefinition(procDefId);
		
		}catch(Exception e){
			throw new WorkFlowException(ExceptionErrorCode.B2002,"当前流程定义未找到!procDefId:"+procDefId,e);
		}
		return rpd;
	}
	/**
	 * 根据流程实例ID获取流程程实例对象
	 * @param procDefId
	 * @return
	 */
	public ProcessInstance getProcessInstance(String procInstId)  {
		if(procInstId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"procInstId is null");
		}
		ProcessInstance processInstance = runtimeService
				.createProcessInstanceQuery()
				.processInstanceId(procInstId)
				.active().singleResult();
		if (processInstance == null) {
			throw new WorkFlowException(ExceptionErrorCode.B2051,"当前流程实例未找到!procInstId:"+procInstId);
		}
		return processInstance;
	}
	
	/**
	 * 根据流程实例ID获取流程程实例对象
	 * @param procDefId
	 * @return
	 */
	public ProcessInstance getProcessInstance(ProcessInputModel processInputModel)  {
		String procInstId=processInputModel.getWf_procInstId();
		if(procInstId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"procInstId is null,processInputModel:"+processInputModel);
		}
		ProcessInstance processInstance = runtimeService
				.createProcessInstanceQuery()
				.processInstanceId(procInstId)
				.active().singleResult();
		if (processInstance == null) {
			throw new WorkFlowException(ExceptionErrorCode.B2051,"当前流程实例未找到!procInstId:"+procInstId);
		}
		return processInstance;
	}
	/**
	 * 根据任务ID获得任务实例
	 * 
	 * @param taskId
	 *            任务ID
	 * @return
	 * @
	 */
	public TaskEntity findTaskById(String taskId)  {
		if(taskId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"taskId is null");
		}
		TaskEntity task = (TaskEntity) taskService.createTaskQuery()
				.taskId(taskId).singleResult();
		if (task == null) {
			throw new WorkFlowException(ExceptionErrorCode.B2052,"当前待办任务未找到!taskId:"+taskId);
		}
		return task;
	}
	
	/**
	 * 根据任务审批人和流程实例ID获得任务实例
	 * 
	 * @param taskId
	 *            任务ID
	 * @return
	 * @
	 */
	public TaskEntity findTaskByAssignee(String procInstId,String assignee)  {
		TaskEntity task = (TaskEntity) taskService.createTaskQuery()
				.processInstanceId(procInstId)
				.taskAssignee(assignee).singleResult();
		if (task == null) {
			throw new WorkFlowException(ExceptionErrorCode.B2052,"当前待办任务未找到!procInstId:"+procInstId+",assignee:"+assignee);
		}
		return task;
	}
	
	/**
	 * @param taskId
	 *            当前任务ID
	 *            
	 * @param activityId
	 *            流程转向执行任务节点ID<br>
	 *            此参数为空，默认为提交操作
	 * @param variables
	 *            流程变量
	 * @
	 */
	public void commitProcess(String taskId,String activityId, Map<String, Object> variables)  {
		if (variables == null) {
			variables = new HashMap<String, Object>();
		}
		taskService.complete(taskId, activityId,variables);
	}
	
	public static ProcessErrorLog buildProcessErrorLog(
			ProcessInputModel processInputModel, String errorMsg, String jsonMsg) {
		ProcessErrorLog processErrorLog = new ProcessErrorLog(
				StringUtils.isEmpty(processInputModel.getWf_procInstId()) ? processInputModel.getWf_curActDefId()
						: processInputModel.getWf_procInstId(),
				processInputModel.getWf_procTitle(),
				processInputModel.getWf_sendUserId() == null ? processInputModel
						.getWf_sender() : processInputModel.getWf_sendUserId(),
				processInputModel.getWf_actionType(), errorMsg, jsonMsg);
		processErrorLog.setAppId(processInputModel.getWf_appId());
		if (processInputModel.getWf_receivers() != null
				&& !processInputModel.getWf_receivers().isEmpty()) {
			processErrorLog.setReceivers(processInputModel.getWf_receivers()
					.toString());
		} else {
			processErrorLog.setReceivers(processInputModel.getWf_receiver());
		}
		processErrorLog.setProcessLogLevel("error");
		//processErrorLog.setDataSource(StringUtils.isEmpty(processInputModel.getWf_data_source())?ProcessErrorLog.DATA_SOURCE_REST:ProcessErrorLog.DATA_SOURCE_MANAGER);
		processErrorLog
				.setProcessDefName(processInputModel.getWf_procDefName());
		return processErrorLog;
	}

	public static ProcessErrorLog buildProcessInfoLog(
			ProcessInstanceModel processInstanceModel, String jsonMsg) {
		ProcessInputModel processInputModel=processInstanceModel.getProcessInputModel();
		ProcessErrorLog processErrorLog = new ProcessErrorLog(
				StringUtils.isEmpty(processInstanceModel.getTopProcInstId()) ? processInputModel.getWf_procInstId()
						: processInstanceModel.getTopProcInstId(),
				processInputModel.getWf_procTitle(),
				processInputModel.getWf_sendUserId()==null?processInputModel.getWf_sender():processInputModel.getWf_sendUserId(),
				processInputModel.getWf_actionType(), "", jsonMsg);
		processErrorLog.setAppId(processInputModel.getWf_appId());
		if(processInputModel.getWf_receivers()!=null&&!processInputModel.getWf_receivers().isEmpty()){
			processErrorLog.setReceivers(processInputModel.getWf_receivers().toString());
		}else{
			processErrorLog.setReceivers(processInputModel.getWf_receiver());
		}
		//processErrorLog.setDataSource(StringUtils.isEmpty(processInputModel.getWf_data_source())?ProcessErrorLog.DATA_SOURCE_REST:ProcessErrorLog.DATA_SOURCE_MANAGER);
		processErrorLog.setProcessLogLevel("info");
		processErrorLog
				.setProcessDefName(processInputModel.getWf_procDefName());
		return processErrorLog;
	}
}
