/**
 * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.modules.flowable.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.core.service.BaseService;
import com.jeeplus.modules.flowable.entity.Flow;
import com.jeeplus.modules.flowable.mapper.FlowMapper;
import com.jeeplus.modules.flowable.service.converter.json.FlowModelService;
import com.jeeplus.modules.flowable.utils.ProcessDefCache;
import com.jeeplus.modules.sys.entity.Role;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.utils.UserUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.engine.task.Comment;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

/**
 * 流程定义相关Service
 *
 * @author jeeplus
 * @version 2016-11-03
 */
@Service
@Transactional(readOnly = true)
public class FlowTaskService extends BaseService {

  @Autowired
  private FlowMapper flowMapper;
  @Autowired
  private RuntimeService runtimeService;
  @Autowired
  private TaskService taskService;
  @Autowired
  private FormService formService;
  @Autowired
  private HistoryService historyService;
  @Autowired
  private RepositoryService repositoryService;
  @Autowired
  private IdentityService identityService;
  @Autowired
  private FlowModelService flowModelService;

  /**
   * 获取待办任务列表
   *
   * @return
   */
  public Page<HashMap<String, String>> todoList(Page<HashMap<String, String>> page, Flow flow) {
    List<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
    String userId = UserUtils.getUser().getId();//ObjectUtils.toString(UserUtils.getUser().getId());
    // =============== 已经签收的任务  ===============
    TaskQuery todoTaskQuery = taskService.createTaskQuery().taskAssignee(userId).active()
      .includeProcessVariables().orderByTaskCreateTime().desc();

    // 设置查询条件
    if (StringUtils.isNotBlank(flow.getProcDefKey())) {
    todoTaskQuery.processDefinitionKey(flow.getProcDefKey());
    }
    if (flow.getBeginDate() != null) {
    todoTaskQuery.taskCreatedAfter(flow.getBeginDate());
    }
    if (flow.getEndDate() != null) {
    todoTaskQuery.taskCreatedBefore(flow.getEndDate());
    }


    // =============== 等待签收的任务  ===============
    List<Role> roleList = UserUtils.getRoleList();
    List<String> roles = Lists.newArrayList();
    for(Role role: roleList){
    roles.add(role.getId());
    }
    TaskQuery toClaimQuery = taskService.createTaskQuery().taskCandidateGroupIn(roles).taskCandidateUser(userId)
      .includeProcessVariables().active().orderByTaskCreateTime().desc();


    // 设置查询条件
    if (StringUtils.isNotBlank(flow.getProcDefKey())) {
    toClaimQuery.processDefinitionKey(flow.getProcDefKey());
    }
    if (flow.getBeginDate() != null) {
    toClaimQuery.taskCreatedAfter(flow.getBeginDate());
    }
    if (flow.getEndDate() != null) {
    toClaimQuery.taskCreatedBefore(flow.getEndDate());
    }

    long taskCount = todoTaskQuery.count();
    long claimCount = toClaimQuery.count();
    long total = taskCount + claimCount;
    page.setCount(total);


    int start = page.getFirstResult();
    int end = page.getFirstResult() + page.getMaxResults();
    // 查询列表
    List<Task> todoList = Lists.newArrayList();
    // 查询列表
    List<Task> toClaimList = Lists.newArrayList();
    if (end == -1) {//不分页
    todoList = todoTaskQuery.list();
    toClaimList = toClaimQuery.list();
    } else {

    if (end <= taskCount) {
      todoList = todoTaskQuery.listPage(start, page.getMaxResults());
    } else if (start < taskCount) {
      todoList = todoTaskQuery.listPage(start, (int) taskCount - start);
      toClaimList = toClaimQuery.listPage(0, end - (int) taskCount);
    } else {
      toClaimList = toClaimQuery.listPage(start - (int) taskCount, page.getMaxResults());
    }
    }

    for (Task task : toClaimList) {
    HashMap map = new HashMap();
    HashMap taskMap = new HashMap();
    HashMap procDefMap = new HashMap();
    taskMap.put("assignee", task.getAssignee());
    taskMap.put("id", task.getId());
    taskMap.put("name", task.getName());
    taskMap.put("createTime", task.getCreateTime());
    taskMap.put("executionId", task.getExecutionId());
    taskMap.put("processInstanceId", task.getProcessInstanceId());
    taskMap.put("processDefinitionId", task.getProcessDefinitionId());
    taskMap.put("taskDefinitionKey", task.getTaskDefinitionKey());
    map.put("task", taskMap);
    map.put("vars", task.getProcessVariables());
    procDefMap.put("name", ProcessDefCache.get(task.getProcessDefinitionId()).getName());
    procDefMap.put("version", ProcessDefCache.get(task.getProcessDefinitionId()).getVersion());
    map.put("procDef", procDefMap);
    map.put("status", "claim");
    page.getList().add(map);
    }

    for (Task task : todoList) {
    HashMap map = new HashMap();
    HashMap taskMap = new HashMap();
    HashMap procDefMap = new HashMap();
    taskMap.put("assignee", task.getAssignee());
    taskMap.put("id", task.getId());
    taskMap.put("createTime", task.getCreateTime());
    taskMap.put("name", task.getName());
    taskMap.put("executionId", task.getExecutionId());
    taskMap.put("processDefinitionId", task.getProcessDefinitionId());
    taskMap.put("processInstanceId", task.getProcessInstanceId());
    taskMap.put("taskDefinitionKey", task.getTaskDefinitionKey());
    map.put("task", taskMap);
    map.put("vars", task.getProcessVariables());
    procDefMap.put("name", ProcessDefCache.get(task.getProcessDefinitionId()).getName());
    procDefMap.put("version", ProcessDefCache.get(task.getProcessDefinitionId()).getVersion());
    map.put("procDef", procDefMap);
    map.put("status", "todo");
    map.put("claimTime", task.getClaimTime());
    page.getList().add(map);
    }



    return page;

  }

  /**
   * 获取已办任务列表
   *
   * @param page
   * @return
   */
  public Page<HashMap<String, String>> historicList(Page<HashMap<String, String>> page, Flow act) {
    String userId = UserUtils.getUser().getId();//ObjectUtils.toString(UserUtils.getUser().getId());

    HistoricTaskInstanceQuery histTaskQuery = historyService.createHistoricTaskInstanceQuery().taskAssignee(userId).finished()
      .includeProcessVariables().orderByHistoricTaskInstanceEndTime().desc();

    // 设置查询条件
    if (StringUtils.isNotBlank(act.getProcDefKey())) {
    histTaskQuery.processDefinitionKey(act.getProcDefKey());
    }
    if (act.getBeginDate() != null) {
    histTaskQuery.taskCompletedAfter(act.getBeginDate());
    }
    if (act.getEndDate() != null) {
    histTaskQuery.taskCompletedBefore(act.getEndDate());
    }

    // 查询总数
    page.setCount(histTaskQuery.count());
    page.initialize();

    // 查询列表
    List<HistoricTaskInstance> histList = Lists.newArrayList();
    if (page.getMaxResults() == -1) {
    histList = histTaskQuery.list();
    } else {
    histList = histTaskQuery.listPage(page.getFirstResult(), page.getMaxResults());
    }

    for (HistoricTaskInstance histTask : histList) {
    HashMap map = new HashMap();
    HashMap taskMap = new HashMap();
    HashMap procDefMap = new HashMap();
    taskMap.put("assignee", histTask.getAssignee());
    taskMap.put("id", histTask.getId());
    taskMap.put("name", histTask.getName());
    taskMap.put("endTime", histTask.getEndTime());
    taskMap.put("executionId", histTask.getExecutionId());;
    taskMap.put("taskDefinitionKey", histTask.getTaskDefinitionKey());
    map.put("task", taskMap);
    map.put("vars", histTask.getProcessVariables());
    procDefMap.put("processInstanceId", histTask.getProcessInstanceId());
    procDefMap.put("processDefinitionId", histTask.getProcessDefinitionId());
    procDefMap.put("name", ProcessDefCache.get(histTask.getProcessDefinitionId()).getName());
    procDefMap.put("version", ProcessDefCache.get(histTask.getProcessDefinitionId()).getVersion());
    map.put("proc", procDefMap);
    map.put("isBack", isBack(histTask));
    try {
      map.putAll(queryProcessState(histTask.getProcessInstanceId()));
    } catch (Exception e1) {
      e1.printStackTrace();
    }

    page.getList().add(map);
    }
    return page;
  }

  /**
   * 获取流转历史任务列表
   *
   * @param procInsId 流程实例
   * @param startFlow  开始活动节点名称
   * @param endFlow  结束活动节点名称
   */
  public List<Flow> histoicFlowList(String procInsId, String startFlow, String endFlow) {
    List<Flow> actList = Lists.newArrayList();
    List<HistoricActivityInstance> list = Lists.newArrayList();
    List<HistoricActivityInstance> historicActivityInstances2 = historyService.createHistoricActivityInstanceQuery().processInstanceId(procInsId)
      .orderByHistoricActivityInstanceStartTime().asc().orderByHistoricActivityInstanceEndTime().asc().list();
    ;
    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances2) {
    if (historicActivityInstance.getEndTime() != null) {
      list.add(historicActivityInstance);
    }
    }

    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances2) {
    if (historicActivityInstance.getEndTime() == null) {
      list.add(historicActivityInstance);
    }
    }
    boolean start = false;
    Map<String, Integer> actMap = Maps.newHashMap();

    for (int i = 0; i < list.size(); i++) {

    HistoricActivityInstance histIns = list.get(i);

    // 过滤开始节点前的节点
    if (StringUtils.isNotBlank(startFlow) && startFlow.equals(histIns.getActivityId())) {
      start = true;
    }
    if (StringUtils.isNotBlank(startFlow) && !start) {
      continue;
    }

    // 只显示开始节点和结束节点，并且执行人不为空的任务
    if (StringUtils.isNotBlank(histIns.getAssignee())
        || "startEvent".equals(histIns.getActivityType())
        || "endEvent".equals(histIns.getActivityType())) {

      // 给节点增加一个序号
      Integer actNum = actMap.get(histIns.getActivityId());
      if (actNum == null) {
        actMap.put(histIns.getActivityId(), actMap.size());
      }

      Flow e = new Flow();
      e.setHistIns(histIns);
      // 获取流程发起人名称
      if ("startEvent".equals(histIns.getActivityType())) {
        List<HistoricProcessInstance> il = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).orderByProcessInstanceStartTime().asc().list();
        if (il.size() > 0) {
        if (StringUtils.isNotBlank(il.get(0).getStartUserId())) {
          User user = UserUtils.get(il.get(0).getStartUserId());
          if (user != null) {
            e.setAssignee(histIns.getAssignee());
            e.setAssigneeName(user.getName());
          }
        }
        }
        e.setComment("【创建流程】");
      }
      if ("endEvent".equals(histIns.getActivityType())) {
        e.setComment("【结束流程】");
      }
      // 获取任务执行人名称
      if (StringUtils.isNotEmpty(histIns.getAssignee())) {
        User user = UserUtils.get(histIns.getAssignee());
        if (user != null) {
        e.setAssignee(histIns.getAssignee());
        e.setAssigneeName(user.getName());
        }
      }
      // 获取意见评论内容
      if (StringUtils.isNotBlank(histIns.getTaskId())) {
        List<Comment> commentList = taskService.getTaskComments(histIns.getTaskId());
        if (commentList.size() > 0) {
        e.setComment(commentList.get(0).getFullMessage());
        }
      }
      if(historyService.createHistoricTaskInstanceQuery().taskId(histIns.getTaskId()).count() == 0){
        e.setComment("【用户撤回】");
      }
      actList.add(e);
    }

    // 过滤结束节点后的节点
    if (StringUtils.isNotBlank(endFlow) && endFlow.equals(histIns.getActivityId())) {
      boolean bl = false;
      Integer actNum = actMap.get(histIns.getActivityId());
      // 该活动节点，后续节点是否在结束节点之前，在后续节点中是否存在
      for (int j = i + 1; j < list.size(); j++) {
        HistoricActivityInstance hi = list.get(j);
        Integer actNumA = actMap.get(hi.getActivityId());
        if ((actNumA != null && actNumA < actNum) || StringUtils.equals(hi.getActivityId(), histIns.getActivityId())) {
        bl = true;
        }
      }
      if (!bl) {
        break;
      }
    }
    }
    return actList;
  }

  /**
   * 获取流程定义列表
   *
   * @param category 流程分类
   */
  public Page<Object[]> processList(Page<Object[]> page, String category) {
    /*
   * 保存两个对象，一个是ProcessDefinition（流程定义），一个是Deployment（流程部署）
   */
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
      .latestVersion().active().orderByProcessDefinitionKey().asc();

    if (StringUtils.isNotEmpty(category)) {
    processDefinitionQuery.processDefinitionCategory(category);
    }

    page.setCount(processDefinitionQuery.count());
    List<ProcessDefinition> processDefinitionList = Lists.newArrayList();
    if (page.getMaxResults() == -1) {//不分页
    processDefinitionList = processDefinitionQuery.list();
    } else {
    processDefinitionList = processDefinitionQuery.listPage(page.getFirstResult(), page.getMaxResults());
    }
    for (ProcessDefinition processDefinition : processDefinitionList) {
    String deploymentId = processDefinition.getDeploymentId();
    Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
    page.getList().add(new Object[]{processDefinition, deployment});
    }
    return page;
  }

  /**
   * 获取流程表单（首先获取任务节点表单KEY，如果没有则取流程开始节点表单KEY）
   *
   * @return
   */
  public String getFormKey(String procDefId, String taskDefKey) {
    String formKey = "";
    if (StringUtils.isNotBlank(procDefId)) {
    if (StringUtils.isNotBlank(taskDefKey)) {
      try {
        formKey = formService.getTaskFormKey(procDefId, taskDefKey);
      } catch (Exception e) {
        formKey = "";
      }
    }
    if (StringUtils.isBlank(formKey)) {
      formKey = formService.getStartFormKey(procDefId);
    }
    if (StringUtils.isBlank(formKey)) {
      formKey = "/404";
    }
    }
    logger.debug("getFormKey: {}", formKey);
    return formKey;
  }

  /**
   * 获取正在运行的流程实例对象
   *
   * @param procInsId
   * @return
   */
  @Transactional(readOnly = false)
  public ProcessInstance getProcIns(String procInsId) {
    return runtimeService.createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
  }

  /**
   * 获取已经结束流程实例对象
   *
   * @param procInsId
   * @return
   */
  @Transactional(readOnly = false)
  public HistoricProcessInstance getFinishedProcIns(String procInsId) {
    return historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).singleResult();
  }


  /**
   * 获取正在运行的流程实例对象列表
   *
   * @param procDefKey
   * @return
   */
  @Transactional(readOnly = false)
  public List<ProcessInstance> getRunngingProcIns(String procDefKey, User user, int[] pageParams) {
    ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processDefinitionKey(procDefKey).active().orderByProcessInstanceId().desc();
    List<ProcessInstance> list = new ArrayList<ProcessInstance>();
    if (User.isAdmin(user.getId())) {
    list = query.listPage(pageParams[0], pageParams[1]);
    } else {
    list = query.involvedUser(user.getId()).listPage(pageParams[0], pageParams[1]);
    }
    return list;
  }


  /**
   * 获取已经结束的流程实例对象列表
   *
   * @param procDefKey
   * @return
   */
  @Transactional(readOnly = false)
  public List<HistoricProcessInstance> getFinishedProcIns(String procDefKey, User user, int[] pageParams) {
    HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().processDefinitionKey(procDefKey).finished().orderByProcessInstanceEndTime().desc();
    List<HistoricProcessInstance> list = new ArrayList<HistoricProcessInstance>();
    if (User.isAdmin(user.getId())) {
    list = query.listPage(pageParams[0], pageParams[1]);
    } else {
    list = query.involvedUser(user.getId()).listPage(pageParams[0], pageParams[1]);
    }
    return list;
  }

  /**
   * 获取我发起的流程申请列表
   *
   * @param user
   * @return
   */
  @Transactional(readOnly = false)
  public Page<HashMap> getMyStartedProcIns(User user, Page<HashMap> page, Flow flow) throws Exception {
    HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().startedBy(user.getId()).includeProcessVariables().orderByProcessInstanceStartTime().desc();
    if (flow.getBeginDate() != null) {
    query.startedAfter(flow.getBeginDate());
    }
    if (flow.getEndDate() != null) {
    query.startedBefore(flow.getEndDate());
    }

    page.setCount(query.count());
    List<HistoricProcessInstance> histList = Lists.newArrayList();
    if (page.getMaxResults() == -1) {//不分页
    histList = query.list();
    } else {
    histList = query.involvedUser(user.getId()).listPage(page.getFirstResult(), page.getMaxResults());
    }
    for (HistoricProcessInstance historicProcessInstance : histList) {

    HashMap map = new HashMap();
    Map state = queryProcessState(historicProcessInstance.getId());
    HashMap procInsMap = new HashMap();
    HashMap procDefMap = new HashMap();
    procInsMap.put("endTime", historicProcessInstance.getEndTime());
    procInsMap.put("startTime", historicProcessInstance.getStartTime());
    procInsMap.put("processInstanceId", historicProcessInstance.getId());
    procDefMap.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
    map.put("vars", historicProcessInstance.getProcessVariables());
    procDefMap.put("name", historicProcessInstance.getProcessDefinitionName());
    procDefMap.put("version", historicProcessInstance.getProcessDefinitionVersion());
    procInsMap.putAll(state);
    map.put("procDef", procDefMap);
    map.put("procIns", procInsMap);
    page.getList().add(map);
    }

    return page;
  }

  /**
   * 启动流程
   *
   * @param procDefKey  流程定义KEY
   * @param businessTable 业务表表名
   * @param businessId  业务表编号
   * @return 流程实例ID
   */
  @Transactional(readOnly = false)
  public String startProcess(String procDefKey, String businessTable, String businessId) {
    return startProcess(procDefKey, businessTable, businessId, "");
  }

  /**
   * 启动流程
   *
   * @param procDefKey  流程定义KEY
   * @param businessTable 业务表表名
   * @param businessId  业务表编号
   * @param title   流程标题，显示在待办任务标题
   * @return 流程实例ID
   */
  @Transactional(readOnly = false)
  public String startProcess(String procDefKey, String businessTable, String businessId, String title) {
    Map<String, Object> vars = Maps.newHashMap();
    return startProcess(procDefKey, businessTable, businessId, title, vars);
  }

  /**
   * 启动流程
   *
   * @param procDefKey  流程定义KEY
   * @param businessTable 业务表表名
   * @param businessId  业务表编号
   * @param title   流程标题，显示在待办任务标题
   * @param vars    流程变量
   * @return 流程实例ID
   */
  @SuppressWarnings("unused")
  @Transactional(readOnly = false)
  public String startProcess(String procDefKey, String businessTable, String businessId, String title, Map<String, Object> vars) {
    //String userId = UserUtils.getUser().getLoginName();//ObjectUtils.toString(UserUtils.getUser().getId())
    // 设置流程变量
    if (vars == null) {
    vars = Maps.newHashMap();
    }

    String userId = (String) vars.get("applyUserId");
    if (userId == null) {
    userId = UserUtils.getUser().getId();
    }
    String userName = UserUtils.get(userId).getName();
    vars.put("userName", userName);

    // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
    identityService.setAuthenticatedUserId(userId);

    // 设置流程标题
    if (StringUtils.isNotBlank(title)) {
    vars.put("title", title);
    }

    // 启动流程
    ProcessInstance procIns = runtimeService.startProcessInstanceByKey(procDefKey, businessTable + ":" + businessId, vars);

    // 更新业务表流程实例ID
    Flow act = new Flow();
    act.setBusinessTable(businessTable);// 业务表名
    act.setBusinessId(businessId);  // 业务表ID
    act.setProcInsId(procIns.getId());
    act.setVars(vars);
    flowMapper.updateProcInsIdByBusinessId(act);
    return act.getProcInsId();
  }

  /**
   * 获取任务
   *
   * @param taskId 任务ID
   */
  public Task getTask(String taskId) {
    return taskService.createTaskQuery().taskId(taskId).singleResult();
  }

  /**
   * 删除任务
   *
   * @param taskId   任务ID
   * @param deleteReason 删除原因
   */
  public void deleteTask(String taskId, String deleteReason) {
    taskService.deleteTask(taskId, deleteReason);
  }

  /**
   * 签收任务
   *
   * @param taskId 任务ID
   * @param userId 签收用户ID（用户登录名）
   */
  @Transactional(readOnly = false)
  public void claim(String taskId, String userId) {
    taskService.claim(taskId, userId);
  }


  /**
   * 提交任务, 并保存意见
   *
   * @param taskId  任务ID
   * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
   * @param comment 任务提交意见的内容
   * @param vars  任务变量
   */
  @Transactional(readOnly = false)
  public void complete(String taskId, String procInsId, String comment, Map<String, Object> vars) {
    complete(taskId, procInsId, comment, "", vars);
  }

  /**
   * 提交任务, 并保存意见
   *
   * @param taskId  任务ID
   * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
   * @param comment 任务提交意见的内容
   * @param title   流程标题，显示在待办任务标题
   * @param vars  任务变量
   */
  @Transactional(readOnly = false)
  public void complete(String taskId, String procInsId, String comment, String title, Map<String, Object> vars) {
    // 添加意见
    if (StringUtils.isNotBlank(procInsId) && StringUtils.isNotBlank(comment)) {
    taskService.addComment(taskId, procInsId, comment);
    }

    // 设置流程变量
    if (vars == null) {
    vars = Maps.newHashMap();
    }

    // 设置流程标题
    if (StringUtils.isNotBlank(title)) {
    vars.put("title", title);
    }




    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    // owner不为空说明可能存在委托任务
    if (StringUtils.isNotBlank(task.getOwner())) {
    DelegationState delegationState = task.getDelegationState();
    switch (delegationState) {
      case PENDING:
        taskService.resolveTask(taskId);
        taskService.complete(taskId, vars);
        break;

      case RESOLVED:
       // 委托任务已经完成
        break;

      default:
        // 不是委托任务
        taskService.complete(taskId, vars);
        break;
    }
    } else {
    // 提交任务
    taskService.complete(taskId, vars);
    }
  }

  /**
   * 完成第一个任务
   *
   * @param procInsId
   */
  public void completeFirstTask(String procInsId) {
    completeFirstTask(procInsId, null, null, null);
  }

  /**
   * 完成第一个任务
   *
   * @param procInsId
   * @param comment
   * @param title
   * @param vars
   */
  public void completeFirstTask(String procInsId, String comment, String title, Map<String, Object> vars) {
    String userId = UserUtils.getUser().getId();
    Task task = taskService.createTaskQuery().taskAssignee(userId).processInstanceId(procInsId).active().singleResult();
    if (task != null) {
    complete(task.getId(), procInsId, comment, title, vars);
    }
  }

  /**
   * 查询流程实例状态
   *
   * @param processInstanceId
   * @return
   * @throws Exception
   */
  public Map queryProcessState(String processInstanceId) throws Exception {
    Map map = new HashMap();
    // 通过流程实例ID查询流程实例
    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
      .processInstanceId(processInstanceId).singleResult();
    if (pi != null) {
    if (pi.isSuspended()) {
      //执行实例
      map.put("code", 0);
      map.put("status", "已挂起");
      return map;
    } else {
      //执行实例
      map.put("code", 1);
      map.put("status", "运行中");
      Task currentTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
      HashMap taskMap = new HashMap();
      taskMap.put("assignee", currentTask.getAssignee());
      taskMap.put("id", currentTask.getId());
      taskMap.put("name", currentTask.getName());
      taskMap.put("executionId", currentTask.getExecutionId());
      taskMap.put("taskDefinitionKey", currentTask.getTaskDefinitionKey());
      map.put("currentTask", taskMap);
      return map;
    }

    } else {
    HistoricProcessInstance pi2 = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    if (pi2 != null) {
      if (pi2.getDeleteReason() == null) {
        map.put("code", 2);
        map.put("status", "正常结束");
        return map;
      } else if (pi2.getDeleteReason().equals("用户撤销")) {
        map.put("code", 3);
        map.put("status", "用户撤销");
        return map;
      } else {
        map.put("code", 4);
        map.put("status", "流程作废");
        map.put("deleteReason",  pi2.getDeleteReason());
        return map;
      }

    } else {
      map.put("code", 5);
      map.put("status", "已删除");
      map.put("deleteReason",  pi2.getDeleteReason());
      return map;
    }

    }
  }

  /**
   * 终止流程实例
   *
   * @param processInstanceId
   */
  public void endProcessInstance(String processInstanceId, String deleteReason) throws Exception {
    runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
  }



  public ProcessEngine processEngine() {
    return ProcessEngines.getDefaultProcessEngine();
  }

  public Map getDiagram(String processId, HttpServletResponse response) {
    Map m = new HashMap();
    try {
//    Model modelData = repositoryService.getModel(id);
//    org.flowable.ui.modeler.domain.Model modelData = flowModelService.getModel(id);
    String processDefId = "";
    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    //流程走完的不显示图
    if (pi == null) {
      processDefId = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult().getProcessDefinitionId();
    }else {
      processDefId = pi.getProcessDefinitionId();
    }
    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
    List<HistoricActivityInstance> historyProcess = getHistoryProcess(processId);
    List<String> activityIds = new ArrayList<>();
    List<String> flows = new ArrayList<>();
    for (HistoricActivityInstance hi : historyProcess) {
      String activityType = hi.getActivityType();
      if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
        flows.add(hi.getActivityId());
      } else if (activityType.equals("userTask") || activityType.equals("startEvent")|| activityType.equals("endEvent")) {
        activityIds.add(hi.getActivityId());
      }
    }
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
    for (Task task : tasks) {
      activityIds.add(task.getTaskDefinitionKey());
    }
    byte[] bpmnBytes = flowModelService.getBpmnXML(bpmnModel);
    m.put("bpmnXml", new String(bpmnBytes));
    m.put("flows", flows);
    m.put("activityIds", activityIds);
    return m;
    } catch (Exception e) {
    e.printStackTrace();
    }
    return null;
  }

  public void tracePhoto(HttpServletResponse httpServletResponse, String processId) throws Exception {
    String processDefId = "";
    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    //流程走完的不显示图
    if (pi == null) {
     processDefId = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult().getProcessDefinitionId();
    }else {
    processDefId = pi.getProcessDefinitionId();
    }

    List<HistoricActivityInstance> historyProcess = getHistoryProcess(processId);
    List<String> activityIds = new ArrayList<>();
    List<String> flows = new ArrayList<>();
    //获取流程图
    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
    for (HistoricActivityInstance hi : historyProcess) {
    String activityType = hi.getActivityType();
    if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
      flows.add(hi.getActivityId());
    } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
      activityIds.add(hi.getActivityId());
    }
    }
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
    for (Task task : tasks) {
    activityIds.add(task.getTaskDefinitionKey());
    }
    ProcessEngineConfiguration engConf = processEngine().getProcessEngineConfiguration();
    //定义流程画布生成器
    ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
    InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
    OutputStream out = null;
    byte[] buf = new byte[1024];
    int legth = 0;
    try {
    out = httpServletResponse.getOutputStream();
    while ((legth = in.read(buf)) != -1) {
      out.write(buf, 0, legth);
    }
    } finally {
    if (in != null) {
      in.close();
    }
    if (out != null) {
      out.close();
    }
    }


  }

  /**
   * 任务历史
   *
   * @param processId 部署id
   */
  public List<HistoricActivityInstance> getHistoryProcess(String processId) {
    List<HistoricActivityInstance> list = historyService // 历史相关Service
      .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
      .processInstanceId(processId) // 执行流程实例id
      .finished().orderByHistoricActivityInstanceEndTime().asc()
      .list();
    return list;
  }


  /**
   * 获取任务节点
   *
   * @param node 查询节点选择
   * @param taskId 任务id
   */
  public FlowElement nextFlowNode(String node, String taskId) {
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    ExecutionEntity ee = (ExecutionEntity)runtimeService.createExecutionQuery()
      .executionId(task.getExecutionId()).singleResult();
    // 当前审批节点
    String crruentActivityId = ee.getActivityId();
    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
    FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
    // 输出连线
    List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
    for (SequenceFlow sequenceFlow : outFlows) {
    //当前审批节点
    if ("now".equals(node)) {
      FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
      return (FlowNode)sourceFlowElement;
    } else if ("next".equals(node)) {
      // 下一个审批节点
      FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
      return  (FlowNode)targetFlow;
    }


    }
    return null;
  }

  /**
   * 流程跟踪图信息
   *
   * @param processInstanceId 流程实例ID
   * @return 封装了各种节点信息
   */
  public List<Map<String, Object>> traceProcess(String processInstanceId) throws Exception {
    Execution execution = runtimeService.createExecutionQuery().executionId(processInstanceId).singleResult();//执行实例
    Object property = PropertyUtils.getProperty(execution, "activityId");
    String activityId = "";
    if (property != null) {
    activityId = property.toString();
    }
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
      .singleResult();
    ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
      .getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
    Collection<FlowElement> activitiList = ProcessDefinitionUtil.getProcess(processInstanceId).getFlowElements();//获得当前任务的所有节点

    List<Map<String, Object>> activityInfos = new ArrayList<Map<String, Object>>();
    for (FlowElement activity : activitiList) {

    boolean currentActiviti = false;
    String id = activity.getId();

    // 当前节点
    if (id.equals(activityId)) {
      currentActiviti = true;
    }

    }

    return activityInfos;
  }


  /**
   * 设置任务组
   *
   * @param vars
   * @param candidateGroupIdExpressions
   */
  private void setTaskGroup(Map<String, Object> vars, Set<Expression> candidateGroupIdExpressions) {
    String roles = "";
    for (Expression expression : candidateGroupIdExpressions) {
    String expressionText = expression.getExpressionText();
    String roleName = identityService.createGroupQuery().groupId(expressionText).singleResult().getName();
    roles += roleName;
    }
    vars.put("任务所属角色", roles);
  }

  /**
   * 设置当前处理人信息
   *
   * @param vars
   * @param currentTask
   */
  private void setCurrentTaskAssignee(Map<String, Object> vars, Task currentTask) {
    String assignee = currentTask.getAssignee();
    if (assignee != null) {
    org.flowable.idm.api.User assigneeUser = identityService.createUserQuery().userId(assignee).singleResult();
    String userInfo = assigneeUser.getFirstName() + " " + assigneeUser.getLastName();
    vars.put("当前处理人", userInfo);
    }
  }


  /**
   * 保存审核意见
   *
   * @param act
   */
  @Transactional(readOnly = false)
  public void auditSave(Flow act, Map vars) {
    act.preUpdate();
    String taskDefKey = act.getTaskDefKey();
    complete(act.getTaskId(), act.getProcInsId(), act.getComment(), vars);

  }


  /**
   * 是否可以回退
   *
   */
  public boolean isBack( HistoricTaskInstance hisTask) {
    ProcessInstance pi = runtimeService.createProcessInstanceQuery()
      .processInstanceId(hisTask.getProcessInstanceId()).singleResult();
    if (pi != null) {
    if (pi.isSuspended()) {
     return false;
    } else {
      Task currentTask = taskService.createTaskQuery().processInstanceId(hisTask.getProcessInstanceId()).singleResult();
      HistoricTaskInstance lastHisTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisTask.getProcessInstanceId()).finished()
        .includeProcessVariables().orderByHistoricTaskInstanceEndTime().desc().list().get(0);

      if (currentTask.getClaimTime() != null) {//用户已签收
        return false;
      }
      if(hisTask.getId().equals(lastHisTask.getId())){
        return true;
      }
      return false;
    }

    } else {
    return false;
    }


  }

}
