package ink.wgink.module.activiti.service.activiti.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.OaNodeException;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.activiti.pojo.dtos.ActivitiFlowNodeDTO;
import ink.wgink.module.activiti.pojo.vos.ActivitiModelVO;
import ink.wgink.module.activiti.service.activiti.IActivitiModelService;
import ink.wgink.module.activiti.service.oa.INodeManageService;
import ink.wgink.util.ResourceUtil;
import ink.wgink.util.xml.XMLUtil;
import org.activiti.bpmn.model.*;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: ActivitiModelServiceImpl
 * @Description: 流程模型
 * @Author: WangGeng
 * @Date: 2021/7/12 22:01
 * @Version: 1.0
 **/
@Service
public class ActivitiModelServiceImpl extends DefaultBaseService implements IActivitiModelService, ModelDataJsonConstants {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private INodeManageService nodeManageService;

    @Override
    public void save(String modelId, Integer modelVersion, ActivitiModelVO activitiModelVO) throws Exception {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new SearchException("模型不存在");
        }
        String deploymentId = null;
        Integer existModelVersion = model.getVersion();
        Integer newModelVersion;
        // 版本相同的模型，如果已经部署，创建新版本；如果没有部署，版本号不变
        if (modelVersion.equals(existModelVersion) && !StringUtils.isBlank(model.getDeploymentId())) {
            LOG.debug("最新版本已经部署，版本号递增");
            newModelVersion = model.getVersion() + 1;
            deploymentId = model.getDeploymentId();
        } else {
            LOG.debug("最新版本未部署，版本号不变");
            newModelVersion = model.getVersion();
        }

        JSONObject modelObject = JSONObject.parseObject(model.getMetaInfo());
        modelObject.put(MODEL_NAME, activitiModelVO.getName());
        modelObject.put(MODEL_DESCRIPTION, activitiModelVO.getDescription());
        model.setMetaInfo(modelObject.toString());
        model.setName(activitiModelVO.getName());
        model.setVersion(newModelVersion);
        repositoryService.saveModel(model);
        repositoryService.addModelEditorSource(model.getId(), activitiModelVO.getJsonXml().getBytes(ISystemConstant.CHARSET_UTF8));

        InputStream svgStream = new ByteArrayInputStream(activitiModelVO.getSvgXml().getBytes(ISystemConstant.CHARSET_UTF8));
        TranscoderInput input = new TranscoderInput(svgStream);

        PNGTranscoder transcoder = new PNGTranscoder();
        // Setup output
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        TranscoderOutput output = new TranscoderOutput(outStream);

        // Do the transformation
        transcoder.transcode(input, output);
        final byte[] result = outStream.toByteArray();
        repositoryService.addModelEditorSourceExtra(model.getId(), result);
        outStream.close();

        LOG.debug("保存节点配置");
        nodeManageService.save(activitiModelVO, modelId, newModelVersion, deploymentId);
    }

    @Override
    public void delete(String modelId) {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new SearchException("模型不存在");
        }
        if (!StringUtils.isBlank(model.getDeploymentId())) {
            throw new RemoveException("已部署的模型不能删除");
        }
        repositoryService.deleteModel(modelId);
        LOG.debug("删除节点配置");
        nodeManageService.delete(modelId, model.getVersion());
    }

    @Override
    public BpmnModel getBpmnModelByProcessDefinitionId(String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        if (bpmnModel == null) {
            throw new SearchException("流程节点不存在");
        }
        return bpmnModel;
    }

    @Override
    public List<FlowNode> listFlowNode(BpmnModel bpmnModel) {
        return bpmnModel.getMainProcess().findFlowElementsOfType(FlowNode.class);
    }

    @Override
    public List<FlowNode> listFlowNodeByProcessDefinitionId(String processDefinitionId) {
        return listFlowNode(getBpmnModelByProcessDefinitionId(processDefinitionId));
    }

    @Override
    public FlowNode getFlowNodeByNodeIdAndProcessDefinitionId(String currentTaskDefinitionKey, String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        return (FlowNode) bpmnModel.getFlowElement(currentTaskDefinitionKey);
    }

    @Override
    public List<SequenceFlow> listNextUserTasksIncomingSequenceFlow(UserTask userTask) {
        List<UserTask> nextUserTasks = listNextUserTasksByUserTask(userTask);
        List<SequenceFlow> incomingFlows = new ArrayList<>();
        for (UserTask nextUserTask : nextUserTasks) {
            incomingFlows.addAll(nextUserTask.getIncomingFlows());
        }
        return incomingFlows;
    }

    @Override
    public List<SequenceFlow> listOutgoingSequenceFlowToNotGateway(UserTask userTask) {
        List<SequenceFlow> sequenceFlows = new ArrayList<>();
        setOutgoingSequenceFlowsNotGateway(userTask, sequenceFlows);
        return sequenceFlows;
    }

    private void setOutgoingSequenceFlowsNotGateway(FlowNode flowNode, List<SequenceFlow> sequenceFlows) {
        List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
            if (targetFlowElement instanceof ExclusiveGateway) {
                setOutgoingSequenceFlowsNotGateway((FlowNode) targetFlowElement, sequenceFlows);
            } else {
                sequenceFlows.add(outgoingFlow);
            }
        }
    }

    @Override
    public List<UserTask> listNextUserTasksByUserTask(UserTask userTask) {
        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
        List<UserTask> nextUserTasks = new ArrayList<>();
        setNextUserTasks(userTask, outgoingFlows, nextUserTasks);
        // 去重
        for (int i = 0; i < nextUserTasks.size(); i++) {
            for (int j = i + 1; j < nextUserTasks.size(); j++) {
                if (StringUtils.equals(nextUserTasks.get(i).getId(), nextUserTasks.get(j).getId())) {
                    nextUserTasks.remove(j);
                    i--;
                    break;
                }
            }
        }
        return nextUserTasks;
    }

    @Override
    public List<UserTask> listBeforeUserTaskByUserTask(UserTask userTask) {
        List<SequenceFlow> incomingFlows = userTask.getIncomingFlows();
        List<UserTask> beforeUserTasks = new ArrayList<>();
        setBeforeUserTasks(userTask, incomingFlows, beforeUserTasks);
        return beforeUserTasks;
    }

    @Override
    public UserTask getFirstUserTaskByProcessDefinitionId(String processDefinitionId) {
        List<FlowNode> listFlowNode = listFlowNodeByProcessDefinitionId(processDefinitionId);
        for (FlowNode flowNode : listFlowNode) {
            if (flowNode instanceof UserTask) {
                return (UserTask) flowNode;
            }
        }
        throw new SearchException("未找到第一个用户任务");
    }

    @Override
    public UserTask getNextUserTask(UserTask currentUserTask) {
        List<SequenceFlow> outgoingFlows = currentUserTask.getOutgoingFlows();
        if (outgoingFlows.size() > 1 || outgoingFlows.size() == 0) {
            throw new OaNodeException("流程错误，下个用户任务节点数只能有1个");
        }
        FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
        if (!(targetFlowElement instanceof UserTask)) {
            throw new OaNodeException("下个节点不是用户任务");
        }
        return (UserTask) targetFlowElement;
    }

    @Override
    public UserTask getNextUserTask(ExclusiveGateway exclusiveGateway, Map<String, Object> reportForm) {
        List<SequenceFlow> outgoingFlows = exclusiveGateway.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : outgoingFlows) {
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof UserTask) {
                if (isExclusiveConditionPass(sequenceFlow.getConditionExpression(), reportForm)) {
                    return (UserTask) targetFlowElement;
                }
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                return getNextUserTask(exclusiveGateway, reportForm);
            }
        }
        throw new OaNodeException("未找到下一节点用户任务");
    }

    @Override
    public UserTask getNextUserTask(String currentTaskDefinitionKey, String processDefinitionId, Map<String, Object> reportForm) {
        FlowNode currentFlowNode = getFlowNodeByNodeIdAndProcessDefinitionId(currentTaskDefinitionKey, processDefinitionId);
        List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : outgoingFlows) {
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof UserTask) {
                return (UserTask) targetFlowElement;
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                LOG.debug("排他网关节点，继续查找");
                ExclusiveGateway exclusiveGateway = (ExclusiveGateway) targetFlowElement;
                return getNextUserTask(exclusiveGateway, reportForm);
            } else if (targetFlowElement instanceof EndEvent) {
                return null;
            }
        }
        throw new OaNodeException("未找到下一节点用户任务");
    }

    @Override
    public HistoricTaskInstance getPrevTask(String processInstanceId, int prevStep) {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().list();
        if (historicTaskInstances == null || historicTaskInstances.isEmpty()) {
            throw new OaNodeException("没有历史任务");
        }
        if (prevStep > historicTaskInstances.size()) {
            throw new OaNodeException("历史任务数量小于查询步数");
        }
        return historicTaskInstances.get(historicTaskInstances.size() - prevStep);
    }

    @Override
    public HistoricTaskInstance getStartTask(String processInstanceId) {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().orderByTaskId().asc().list();
        if (historicTaskInstances == null || historicTaskInstances.isEmpty()) {
            throw new OaNodeException("没有历史任务");
        }
        return historicTaskInstances.get(0);
    }

    @Override
    public StartEvent getStartEvent(List<FlowNode> flowNodes) {
        if (flowNodes == null || flowNodes.isEmpty()) {
            return null;
        }
        for (FlowNode flowNode : flowNodes) {
            if (flowNode instanceof StartEvent) {
                return (StartEvent) flowNode;
            }
        }
        return null;
    }

    @Override
    public List<ActivitiFlowNodeDTO> listActivitiFlowNodeByModel(List<FlowNode> flowNodes) {
        List<ActivitiFlowNodeDTO> activitiFlowNodeDTOs = new ArrayList<>();
        for (FlowNode flowNode : flowNodes) {
            ActivitiFlowNodeDTO activitiFlowNodeDTO = new ActivitiFlowNodeDTO();
            activitiFlowNodeDTO.setId(flowNode.getId());
            activitiFlowNodeDTO.setName(flowNode.getName());
            activitiFlowNodeDTO.setSummary(flowNode.getDocumentation());
            if (flowNode instanceof StartEvent) {
                StartEvent startEvent = (StartEvent) flowNode;
                activitiFlowNodeDTO.setFormKey(startEvent.getFormKey());
                activitiFlowNodeDTO.setType(StartEvent.class.getSimpleName());
            } else if (flowNode instanceof EndEvent) {
                activitiFlowNodeDTO.setType(EndEvent.class.getSimpleName());
            } else if (flowNode instanceof UserTask) {
                UserTask userTask = (UserTask) flowNode;
                activitiFlowNodeDTO.setFormKey(userTask.getFormKey());
                activitiFlowNodeDTO.setType(UserTask.class.getSimpleName());
            } else {
                continue;
            }
            activitiFlowNodeDTOs.add(activitiFlowNodeDTO);
        }
        return activitiFlowNodeDTOs;
    }

    @Override
    public List<ActivitiFlowNodeDTO> listFlowNodeByDeploymentId(String deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        if (processDefinition == null) {
            throw new SearchException("流程定义不存在，请检查流程部署情况");
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        List<FlowNode> flowNodes = listFlowNode(bpmnModel);
        return listActivitiFlowNodeByModel(flowNodes);
    }

    @Override
    public JSONObject getEditorJson(String modelId) throws UnsupportedEncodingException {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            throw new SearchException("模型不存在");
        }
        JSONObject result;
        if (StringUtils.isNotEmpty(model.getMetaInfo())) {
            result = JSONObject.parseObject(model.getMetaInfo());
        } else {
            result = new JSONObject();
            result.put(MODEL_NAME, model.getName());
        }
        result.put(MODEL_ID, model.getId());
        result.put("modelVersion", model.getVersion());
        String readTree = new String(repositoryService.getModelEditorSource(model.getId()), ISystemConstant.CHARSET_UTF8);
        JSONObject editorJson = JSONObject.parseObject(readTree);
        result.put("model", editorJson);
        return result;
    }

    @Override
    public JSONObject getStencilset() throws IOException {
        String content;
        try (InputStream jarResourceInputStream = ResourceUtil.getJarResourceInputStream("static/stencilset.json");
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(jarResourceInputStream));) {
            content = bufferedReader.lines().collect(Collectors.joining("\n"));
        } catch (IOException e) {
            throw e;
        }
        JSONObject jsonObject = JSONObject.parseObject(content);
        // 设置默认且唯一的信息
        JSONArray propertyPackagesJsonArray = jsonObject.getJSONArray("propertyPackages");

        JSONObject processIdPackageJsonObject = propertyPackagesJsonArray.getJSONObject(0);
        JSONArray processIdPackagePropertiesJsonArray = processIdPackageJsonObject.getJSONArray("properties");
        JSONObject processIdJsonObject = processIdPackagePropertiesJsonArray.getJSONObject(0);
        processIdJsonObject.put("value", "P" + System.currentTimeMillis());
        return jsonObject;
    }

    @Override
    public void getProcessImage(HttpServletResponse response, String deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        if (processDefinition == null) {
            throw new SearchException("流程定义不存在，请检查流程部署情况");
        }
        String fontName = "宋体";
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        CustomProcessDiagramGenerator customProcessDiagramGenerator = new CustomProcessDiagramGenerator();
        response.setContentType("image/png");
        try (InputStream inputStream = customProcessDiagramGenerator.generateDiagram(bpmnModel, "png", new ArrayList<>(), new ArrayList<>(), fontName, fontName, fontName, null, 1.0D);
             OutputStream outputStream = response.getOutputStream();
        ) {
            byte[] buf = new byte[1024];
            for (int size; (size = inputStream.read(buf)) != -1; ) {
                outputStream.write(buf, 0, size);
            }
            outputStream.flush();
        } catch (IOException e) {
            throw new SystemException("流程图生成错误", e);
        }
    }

    @Override
    public void getRuntimeProcessImage(HttpServletResponse response, String processInstanceId) {
        response.setContentType("image/png");
        try (InputStream inputStream = getRuntimeProcessImageInputStream(processInstanceId);
             OutputStream outputStream = response.getOutputStream();
        ) {
            byte[] buf = new byte[1024];
            for (int size; (size = inputStream.read(buf)) != -1; ) {
                outputStream.write(buf, 0, size);
            }
            outputStream.flush();
        } catch (IOException e) {
            throw new SystemException("流程图生成错误", e);
        }
    }

    @Override
    public String getProcessXml(String processDefinitionId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        if (processDefinition == null) {
            throw new SearchException("流程定义不存在");
        }
        String result;
        try (InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            StringBuilder xmlSB = new StringBuilder();
            for (String line; (line = bufferedReader.readLine()) != null; ) {
                xmlSB.append(line);
            }
            result = XMLUtil.formatXmlString(xmlSB.toString());
        } catch (IOException e) {
            throw new SystemException(e);
        }
        return result;
    }

    /**
     * 设置下一个用户任务列表
     *
     * @param outgoingFlow
     * @param nextUserTasks
     */
    private void setNextUserTasks(SequenceFlow outgoingFlow, List<UserTask> nextUserTasks) {
        FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
        if (targetFlowElement instanceof UserTask) {
            LOG.debug("下一个节点为用户任务，添加");
            nextUserTasks.add((UserTask) targetFlowElement);
            return;
        }
        if (targetFlowElement instanceof ExclusiveGateway) {
            LOG.debug("下一个节点为互斥网关，递归");
            ExclusiveGateway exclusiveGateway = ((ExclusiveGateway) targetFlowElement);
            setNextUserTasks(exclusiveGateway, exclusiveGateway.getOutgoingFlows(), nextUserTasks);
        }
    }

    /**
     * 设置之前的用户任务
     *
     * @param currentFlowNode
     * @param incomingFlows
     * @param beforeUserTasks
     */
    private void setBeforeUserTasks(FlowNode currentFlowNode, List<SequenceFlow> incomingFlows, List<UserTask> beforeUserTasks) {
        if (currentFlowNode instanceof StartEvent) {
            return;
        }
        if (incomingFlows.isEmpty()) {
            throw new SearchException("流程错误，用户任务输入序列流不存在");
        }
        for (SequenceFlow incomingFlow : incomingFlows) {
            FlowElement sourceFlowElement = incomingFlow.getSourceFlowElement();
            if (sourceFlowElement instanceof UserTask) {
                UserTask beforeUserTask = (UserTask) sourceFlowElement;
                setBeforeUserTasks(beforeUserTask, beforeUserTask.getIncomingFlows(), beforeUserTasks);
                beforeUserTasks.add(beforeUserTask);
                continue;
            }
            if (sourceFlowElement instanceof ExclusiveGateway) {
                ExclusiveGateway exclusiveGateway = (ExclusiveGateway) sourceFlowElement;
                setBeforeUserTasks(exclusiveGateway, exclusiveGateway.getIncomingFlows(), beforeUserTasks);
            }
        }
    }

    /**
     * 设置下一个用户任务列表
     *
     * @param currentFlowNode
     * @param outgoingFlows
     * @param nextUserTasks
     */
    private void setNextUserTasks(FlowNode currentFlowNode, List<SequenceFlow> outgoingFlows, List<UserTask> nextUserTasks) {
        if (outgoingFlows.isEmpty()) {
            throw new SearchException("流程错误。用户任务流出序列流不存在");
        }
        if (currentFlowNode instanceof UserTask) {
            LOG.debug("当前节点为用户任务");
            if (outgoingFlows.size() > 1) {
                throw new SearchException("流程错误。用户任务流出序列流数量大于1");
            }
            setNextUserTasks(outgoingFlows.get(0), nextUserTasks);
            return;
        }
        if (currentFlowNode instanceof ExclusiveGateway) {
            LOG.debug("当前节点为互斥网关，遍历");
            for (SequenceFlow outgoingFlow : outgoingFlows) {
                setNextUserTasks(outgoingFlow, nextUserTasks);
            }
            return;
        }
    }


    /**
     * 获取运行流程图输入流
     *
     * @param processInstanceId
     * @return
     */
    public InputStream getRuntimeProcessImageInputStream(String processInstanceId) {
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        HistoricProcessInstance processInstanceHistory;
        String processDefinitionId;
        if (processInstance == null) {
            //查询已经结束的流程实例
            processInstanceHistory = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null) {
                return null;
            } else {
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
            }
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        //获取流程实例当前的节点，需要高亮显示
        List<String> highLightedActivitiIds = new ArrayList<>();
        if (processInstance != null) {
            // 正在运行的流程
            List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
            // 先添加历史节点
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
            if (!historicActivityInstances.isEmpty()) {
                for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                    if (isActiveActivityId(historicActivityInstance.getActivityId(), activeActivityIds)) {
                        continue;
                    }
                    highLightedActivitiIds.add(historicActivityInstance.getActivityId());
                }
            }
            // 添加现有节点
            for (String activeActivityId : activeActivityIds) {
                highLightedActivitiIds.add("#" + activeActivityId);
            }
        } else {
            // 历史流程
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
            if (!historicActivityInstances.isEmpty()) {
                for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                    highLightedActivitiIds.add(historicActivityInstance.getActivityId());
                }
            }
        }
        List<String> listSequenceFlows = listSequenceFlows(bpmnModel, highLightedActivitiIds);
        CustomProcessDiagramGenerator customProcessDiagramGenerator = new CustomProcessDiagramGenerator();
        return customProcessDiagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitiIds, listSequenceFlows,
                fontName, fontName, fontName, null, 1D);
    }

    /**
     * 判断历史节点是否是激活节点
     *
     * @param historyActivityId
     * @param activeActivityIds
     * @return
     */
    private boolean isActiveActivityId(String historyActivityId, List<String> activeActivityIds) {
        if (activeActivityIds == null || activeActivityIds.isEmpty()) {
            return false;
        }
        for (String activeActivityId : activeActivityIds) {
            if (StringUtils.equals(historyActivityId, activeActivityId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 序列流列表
     *
     * @param bpmnModel              模型
     * @param highLightedActivitiIds 高亮的活动ID
     * @return
     */
    private List<String> listSequenceFlows(BpmnModel bpmnModel, List<String> highLightedActivitiIds) {
        Set<String> flowSet = new HashSet<>();
        // 获取有关的点
        List<FlowNode> flowElementsOfType = bpmnModel.getProcesses().get(0).findFlowElementsOfType(FlowNode.class);
        List<FlowNode> activitiFlowNode = new ArrayList<>();
        // 加载高亮的节点
        for (String highLightedActivitiId : highLightedActivitiIds) {
            String activitiId = highLightedActivitiId;
            if (activitiId.startsWith("#")) {
                activitiId = highLightedActivitiId.substring(1);
            }
            for (FlowNode flowNode : flowElementsOfType) {
                if (StringUtils.equals(flowNode.getId(), activitiId)) {
                    activitiFlowNode.add(flowNode);
                    break;
                }
            }
        }
        // 找出高亮节点之间的连线
        for (int i = 0; i < activitiFlowNode.size() - 1; i++) {
            FlowNode flowNode = activitiFlowNode.get(i);
            List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();

            FlowNode nextFlowNode = activitiFlowNode.get(i + 1);
            List<SequenceFlow> nextIncomingFlows = nextFlowNode.getIncomingFlows();
            // 前节点的出与后节点的入相同，则有关系
            for (SequenceFlow outgoingFlow : outgoingFlows) {
                for (SequenceFlow nextIncomingFlow : nextIncomingFlows) {
                    if (StringUtils.equals(outgoingFlow.getId(), nextIncomingFlow.getId())) {
                        flowSet.add(outgoingFlow.getId());
                    }
                }
            }
        }
        return new ArrayList<>(flowSet);
    }

    /**
     * 排他条件判断通过
     *
     * @param conditionExpression 条件表达式
     * @param reportFormMap       表单变量
     * @return
     */
    private static boolean isExclusiveConditionPass(String conditionExpression, Map<String, Object> reportFormMap) {
        if (StringUtils.isBlank(conditionExpression)) {
            LOG.debug("排他网关条件表达式为空");
            return false;
        }
        if (reportFormMap.isEmpty()) {
            LOG.debug("上报表单为空");
            return false;
        }
        //分割表达式
        String[] expressionArray = conditionExpression.split("[{}$&]");
        for (String expression : expressionArray) {
            // 是否包含条件字段
            if (!expression.contains(IActivitiModelService.EXCLUSIVE_GATEWAY_CONDITION_KEY)) {
                continue;
            }
            // 表单中是否包含条件字段
            if (!reportFormMap.containsKey(IActivitiModelService.EXCLUSIVE_GATEWAY_CONDITION_KEY)) {
                continue;
            }
            if (expression.contains("==")) {
                String[] primes = expression.split("==");
                String valExpression = primes[1].trim();
                if (valExpression.startsWith("'")) {
                    valExpression = valExpression.substring(1);
                }
                if (valExpression.endsWith("'")) {
                    valExpression = valExpression.substring(0, valExpression.length() - 1);
                }
                if (primes.length == 2 && valExpression.equals(reportFormMap.get(IActivitiModelService.EXCLUSIVE_GATEWAY_CONDITION_KEY))) {
                    return true;
                }
            }
        }
        return false;
    }

}
