package org.springblade.flow.base.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import groovy.lang.GroovyShell;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.groovy.control.MultipleCompilationErrorsException;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.delegate.JavaDelegate;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.delegate.ActivityBehavior;
import org.springblade.flow.engine.assembly.*;
import org.springblade.flow.engine.assembly.prop.UserTaskAdvancedSettingDTO;
import org.springblade.flow.engine.assembly.prop.UserTaskBasicPropDTO;
import org.springblade.flow.engine.assembly.prop.UserTaskNodeEventDTO;
import org.springblade.flow.engine.custom.constants.BasicActivitiConstants;
import org.springblade.flow.engine.entity.FlowEngineEntity;
import org.springblade.flow.engine.enums.FlowNodeTypeEnum;
import org.springblade.flow.engine.enums.FlowRequestMethodEnum;
import org.springblade.flow.engine.enums.FlowScriptTypeEnum;
import org.springblade.flow.engine.enums.FlowTaskOperatorEnum;
import org.springblade.flow.engine.exception.ActivitiWorkFlowException;
import org.springblade.flow.engine.model.flowengine.shuntjson.childnode.*;
import org.springblade.flow.engine.model.flowengine.shuntjson.childnode.Properties;
import org.springblade.flow.engine.model.flowengine.shuntjson.nodejson.ChildNodeList;
import org.springblade.flow.engine.model.flowengine.shuntjson.nodejson.ConditionList;
import org.springblade.flow.engine.service.FlowEngineService;
import org.springblade.flow.exception.WorkFlowException;
import org.springblade.flow.util.JsonUtilEx;

import java.util.*;

import static org.flowable.engine.impl.bpmn.behavior.CallActivityBehavior.CALLED_ELEMENT_TYPE_KEY;
import static org.springblade.flow.engine.custom.constants.BasicActivitiConstants.exActivitiPrefixURL;
import static org.springblade.flow.engine.custom.constants.BasicActivitiConstants.extensionAttributeName;

/**
 * @author LoveMyOrange
 * @create 2021-09-20 19:09
 * @desc 动态创建 Activiti 流程图对象
 */
@SuppressWarnings("all")
@Slf4j
public class BpmnModelUtils {

    /**
     * 所有的连线都会先放到此对象中
     */
    private ThreadLocal<List<SequenceFlow>> sequenceFlowList = new ThreadLocal();
    /**
     * 设置BpmnModel 的一些全局信息
     * bpmnModel 上添加扩展属性是 设置到哪了??
     * 设置到 <definitions/></definitions> 元素上了 但实际上 这里不需要扩展属性 没必要...
     * 将扩展元素添加到此处必然是不合适的 因为首先一个bpmn文件可以拥有多个process 定义在process元素上更合适
     */
    public static BpmnModel setBpmnModelInfo(BpmnModel bpmnModel, FlowEngineEntity flowEngineEntity){
//        //扩展属性的JSON值 直接使用JSON来存取 不然的话 需要在XML中定义太多扩展属性了()
//        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
//        ActivityExPropertyDTO activityExPropertyDTO = new ActivityExPropertyDTO();
//        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
//        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
//        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
//        String tables = flowEngineEntity.getTables();
//        activityExPropertyDTO.setFormType(flowEngineEntity.getFormType());
//        activityExPropertyDTO.setTablesInfo(tables);
//        activityExPropertyDTO.setFlowCategory(flowEngineEntity.getCategory());
//        activityExPropertyDTO.setFlowType(flowEngineEntity.getType()+"");
//        activityExPropertyDTO.setFlowTemplateJson(flowEngineEntity.getFlowTemplateJson());
//        activityExPropertyDTO.setFormData(flowEngineEntity.getFormData());
//        activityExPropertyDTO.setFlowVersion(flowEngineEntity.getVersion());
//        extensionAttribute.setValue(JSONObject.toJSONString(activityExPropertyDTO));
//        Process mainProcess = bpmnModel.getMainProcess();
//        //全局扩展属性
//        mainProcess.addAttribute(extensionAttribute);
        //这种是将扩展元素 添加到 <definitions>元素上 但是将扩展元素添加到此处必然是不合适的 因为首先一个bpmn文件可以拥有多个process 定义在process元素上更合适
//        bpmnModel.addDefinitionsAttribute(extensionAttribute);
        bpmnModel.setTargetNamespace(flowEngineEntity.getCategory());//这行代码没用 任性...
        //为<definitions/> 元素加扩展元素的命名空间
        bpmnModel.addNamespace(BasicActivitiConstants.exActivitiPrefix, BasicActivitiConstants.exActivitiPrefixURL);
        return bpmnModel;
    }
    /**
     * 组装Process对象 ,一个bpmnModel 对象中 可以装载多个 Process对象,
     * 也即 一个bpmn文件中 可以出现 N个 毫不相干的流程图 但是实际上出现了反而界限不明确了, 所以没有必要这么做
     */
    public  static Process createProcess(FlowEngineEntity flowEngineEntity, Set<String> set){
        Process process = new Process();
        process.setId(BasicActivitiConstants.activitiPrefix+flowEngineEntity.getEnCode());//
        process.setName(flowEngineEntity.getFullName());
        process.setExecutable(true);//设为可执行
        process.setDocumentation(flowEngineEntity.getDescription());
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        //扩展属性的JSON值 直接使用JSON来存取 不然的话 需要在XML中定义太多扩展属性了()
        GlobalExPropertyDTO bpmnExPropertyDTO=new GlobalExPropertyDTO();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        String tables = flowEngineEntity.getTables();
        bpmnExPropertyDTO.setFormType(flowEngineEntity.getFormType());
        bpmnExPropertyDTO.setTablesInfo(tables);
        bpmnExPropertyDTO.setFlowCategory(flowEngineEntity.getCategory());
        bpmnExPropertyDTO.setFlowType(flowEngineEntity.getType());
        bpmnExPropertyDTO.setFlowFormType(flowEngineEntity.getFormType());
        bpmnExPropertyDTO.setFlowTemplateJson(flowEngineEntity.getFlowTemplateJson());
        bpmnExPropertyDTO.setFormData(flowEngineEntity.getFormData());
        bpmnExPropertyDTO.setFlowVersion(flowEngineEntity.getVersion());
        bpmnExPropertyDTO.setFieldSet(set);
        extensionAttribute.setValue(JSONObject.toJSONString(bpmnExPropertyDTO));
        //全局扩展属性
        process.addAttribute(extensionAttribute);
        return process;
    }

    /**
        组装开始节点
     *  在钉钉的 流程图中 是没有开始节点的  自己组装就可以了
//     * @param applyUserActivityId 发起节点的Id
     * @return
     */
    public static  StartEvent createStartEvent(Process process){
        StartEvent startEvent = new StartEvent();
        startEvent.setId(BasicActivitiConstants.startEventId);
        startEvent.setName("流程启动");
        startEvent.setInitiator(BasicActivitiConstants.startEventInitiator);//发起人
        startEvent.setDocumentation("流程启动");
        process.addFlowElement(startEvent);
        return startEvent;
    }

    /**
     * 解析连线条件对象  得到连线条件表达式
     * @return  连线上的表达式
     */
    public  static  String parseCondition(List<ProperCond> conditions){
        if(conditions==null || conditions.isEmpty()){
            return "";
        }
        StringBuilder expression = new StringBuilder();
        for (int i = 0; i < conditions.size(); i++) {
            String field = conditions.get(i).getField();
            String filedValue = conditions.get(i).getFiledValue();
            String logic = conditions.get(i).getLogic();
            String symbol = conditions.get(i).getSymbol();
            //替换不等于
            if ("<>".equals(symbol)) {
                symbol = "!=";
            }
            expression.append(" "+field+"").append(" "+symbol+" ").append(" "+filedValue+" ");
            //如果是最后一个  -> 不用带logic
            if (!StringUtils.isEmpty(logic)) {
                if (i != conditions.size() - 1) {
                    expression.append(" " + logic + " ");
                }
            }
        }
        return "${ " +expression.toString() +" }";
    }

    /**
     * 转成ascii码
     **/
    private static String stringToAscii(String value) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            sbu.append((int) chars[i]);
        }
        return sbu.toString();
    }

    /**
     * 创建连线节点  不带连线的id
     * @param fromId
     * @param toId
     * @param sequenceFlowList
     * @return
     */
    public static SequenceFlow createSequenceFlowWithOutNodeId(String fromId, String toId, List<SequenceFlow> sequenceFlowList){
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId(getId("sequenceFlow",""));
        sequenceFlow.setSourceRef(fromId);
        sequenceFlow.setTargetRef(toId);
        sequenceFlowList.add(sequenceFlow);
        return sequenceFlow;
    }

    /**
     * 创建连线节点 带 连线的id
     */
    public static SequenceFlow createSequenceFlowWithNodeId(
            String fromId, String toId,
            List<SequenceFlow> sequenceFlowList,
            String nodeId,
            Map<String, Object> conditionListMap,
            Process process
    ){
            SequenceFlow sequenceFlow = new SequenceFlow();
            sequenceFlow.setSourceRef(fromId);
            sequenceFlow.setTargetRef(toId);
            if(StringUtils.isBlank(nodeId)){
                sequenceFlow.setId(getId("sequenceFlow",""));
            }
            else{
                sequenceFlow.setId(nodeId);
                ConditionList conditionList = (ConditionList) conditionListMap.get(nodeId);
                String title = conditionList.getTitle();
                String content = conditionList.getContent();
                Boolean isDefault = conditionList.getIsDefault();
                List<ProperCond> conditions = conditionList.getConditions();
                String conditionExpression = BpmnModelUtils.parseCondition(conditions);
                sequenceFlow.setName(content);
                sequenceFlow.setDocumentation(title);
                sequenceFlow.setConditionExpression(conditionExpression);
                if(isDefault){
//                    ExclusiveGateway exclusiveGateway = (ExclusiveGateway) process.getFlowElement(fromId);
//                    exclusiveGateway.setDefaultFlow(sequenceFlow.getId());
                }
            }

            ExtensionAttribute extensionAttribute = new ExtensionAttribute();
            SequenceFlowExPropertyDTO activityExPropertyDTO = new SequenceFlowExPropertyDTO();
            extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
            extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
            extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
            activityExPropertyDTO.setConditionNodeList((ConditionList) conditionListMap.get(nodeId));
            extensionAttribute.setValue(JSONObject.toJSONString(activityExPropertyDTO));
            sequenceFlow.addAttribute(extensionAttribute);
            sequenceFlowList.add(sequenceFlow);
            return sequenceFlow;
//            process.addFlowElement(sequenceFlow);
//        }
//        else{
//            //有分支的情况下
//            List<ChildNode> conditionNodes = childNode.getConditionNodes();
//            //如果是条件 那么应当创建排他网关
//            if(FlowCondition.CONDITION.equals(conditionType) || FlowCondition.CONDITION.equals(type)){
//                ExclusiveGateway exclusiveGateway = createExclusiveGateway(childNode, process);
//                for (ChildNode conditionNode : conditionNodes) {
//                    Properties nodeProperties = conditionNode.getProperties();
//                    SequenceFlow sequenceFlow = new SequenceFlow();
//                    sequenceFlow.setId(conditionNode.getNodeId());
//                    sequenceFlow.setName(nodeProperties.getTitle());
//                    sequenceFlow.setDocumentation(conditionNode.getContent());
//                    List<ProperCond> conditions = nodeProperties.getConditions();
//                    //为连线设置条件
//                    StringBuilder conditionExpression=new StringBuilder("${");
//                    if(!conditions.isEmpty()){
//                        if(conditions.size()==1){
//                            ProperCond properCond = conditions.get(0);
//                            String symbol = properCond.getSymbol();
//                            if("<>".equals(symbol)){
//                                symbol="!=";
//                            }
//                            conditionExpression.append(properCond.getField()).append(symbol).append(properCond.getFiledValue()).append("}");
//                            sequenceFlow.setConditionExpression(conditionExpression.toString());
//                        }
//                        else {
//                            //获取最后一条连线
//                            ProperCond properCond = conditions.get(conditions.size() - 1);
//                            //移除最后一条
//                            conditions.remove(conditions.size()-1);
//                            for (ProperCond condition : conditions) {
//                                String symbol = condition.getSymbol();
//                                if("<>".equals(symbol)){
//                                    symbol="!=";
//                                }
//                                conditionExpression.append(condition.getField()).append(" ")
//                                        .append(symbol).append(" ")
//                                        .append(condition.getFiledValue()).append(" ")
//                                        .append(condition.getLogic()).append(" ");
//                            }
//                            //
//                            String lastSymbol = properCond.getSymbol();
//                            if("<>".equals(lastSymbol)){
//                                lastSymbol="!=";
//                            }
//                            //拼接最后一条
//                            conditionExpression.append(properCond.getField()).append(" ")
//                                    .append(properCond.getSymbol()).append(" ")
//                                    .append(properCond.getFiledValue()).append(" ")
//                                    .append("}");
//                            //设置条件
//                            sequenceFlow.setConditionExpression(conditionExpression.toString());
//                        }
//                    }
//                    //设置默认输出流
//                    if(nodeProperties.getIsDefault()){
//                        exclusiveGateway.setDefaultFlow(conditionNode.getNodeId());
//                    }
//                    //设置来源目标节点
//                    sequenceFlow.setSourceRef(exclusiveGateway.getId());
////                sequenceFlow.setTargetRef(conditionNode.getChildNode().getNodeId());
//                    //设置目标接节点
//
//                    //判断
//
//                }
//                  /*
//                    判断当前节点是否有子节点  &&
//                    判断条件节点的第一个node 中是否有子节点 如果没有那么就是真的结束了
//                     */
////                if(childNode.getChildNode()==null && childNode.getConditionNodes().get(0).getChildNode()==null){
////                    EndEvent endEvent = createEndEvent();//
////                    for (SequenceFlow sequenceFlow : sequenceFlowList) {
////                        sequenceFlow.setTargetRef(endEvent.getId());
////                        process.addFlowElement(sequenceFlow);
////                    }
////                    endEvent.setIncomingFlows(sequenceFlowList);
////                }
////                else{
////                    //递归(应该把sequenceList带到方法入参  为sequenceFlow的 targetRef设置值)
////
////                }
//            }
//
//            else if (FlowCondition.INTERFLOW.equals(conditionType) ||FlowCondition.INTERFLOW.equals(type)){
//
//            }
//        }
//        return sequenceFlowList;
    }

    public static SequenceFlow createSequenceFlowWithExpression(String fromId,String toId,List<SequenceFlow> sequenceFlowList,String expression,String sequenceFlowName){
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId(getId("sequenceFlow",""));
        sequenceFlow.setSourceRef(fromId);
        sequenceFlow.setTargetRef(toId);
        if(StringUtils.isNotBlank(expression)){
            sequenceFlow.setConditionExpression(expression);
        }
        if(StringUtils.isNotBlank(sequenceFlowName)){
            sequenceFlow.setName(sequenceFlowName);
        }
        sequenceFlowList.add(sequenceFlow);
        return  sequenceFlow;
    }


    private static  void setCounterSignInfo(UserTask userTask,Integer counterSign,Long countersignRatio){
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics= new MultiInstanceLoopCharacteristics();
        String id = userTask.getId();
        multiInstanceLoopCharacteristics.setInputDataItem(id+"assigneeList");//collection属性
        multiInstanceLoopCharacteristics.setElementVariable("assignee");
        multiInstanceLoopCharacteristics.setSequential(false);//不管是 或签还是会签 都是并行会签
        userTask.setAssignee("${assignee}");
        //如果是或签 那么设置一下完成条件 只有会签中的任何一个人完成  那么都算会签完成了
        if(counterSign==0){
            //完成的会签实例数 除 总会签实例数 >0
            multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances > 0}");
        }
        else{
            //会签完成比例
            String strRate=countersignRatio+"";
            Integer rate = Integer.valueOf(strRate);
            multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances >= "+rate+"}");
        }
        userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
    }

    /**
     * 创建用户节点
     */
    public static String createUserTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        UserTask userTask = new UserTask();
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        //扩展属性的JSON值 直接使用JSON来存取 不然的话 需要在XML中定义太多扩展属性了()
        UserTaskExPropertyDTO activityExPropertyDTO = new UserTaskExPropertyDTO();

        UserTaskBasicPropDTO userTaskBasicPropDTO=new UserTaskBasicPropDTO();
        UserTaskAdvancedSettingDTO userTaskAdvancedSettingDTO=new UserTaskAdvancedSettingDTO();
        UserTaskNodeEventDTO userTaskNodeEventDTO=new UserTaskNodeEventDTO();
        userTaskBasicPropDTO.setChildNodeListJson(JsonUtilEx.getObjectToString(childNodeList));
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);

        Properties properties = childNode.getProperties();
        //1.0 用户节点基本信息设置
        String userTaskId = childNode.getNodeId() /*getId(childNode.getType(), childNode.getNodeId())*/;
        userTask.setId(userTaskId);
        userTask.setName(/*properties.getTitle()*/childNode.getContent());
        //content 和 description  都放到这个字段中 逗号隔开就行  也可以存储到扩展属性中 但是没啥必要
        userTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());
        //发起节点需要单独判断一下  因为 发起节点的属性 只有3个tab页
        if("start".equals(childNode.getType())){
            //1.1 发起节点专有的  发起人tab页信息
            List<String> initiator = properties.getInitiator();
            if(initiator!=null&&!initiator.isEmpty()){
                userTaskBasicPropDTO.setStartProcessAuthUsers(initiator);
            }
            List<String> initiatePos = properties.getInitiatePos();
            if(initiatePos!=null && !initiatePos.isEmpty()){
                userTaskBasicPropDTO.setStartProcessAuthPosition(initiatePos);
            }
            userTaskBasicPropDTO.setAssigneeType(FlowTaskOperatorEnum.InitiatorMe.getCode());

            //1.2 表单权限 不管是发起节点还是审批节点都有 所以提到下面 统一执行
            //1.3 流程事件Tab页->
            //发起节点 是发起节点的 撤回事件
            // 自定义撤回事件 (疑问? 为啥这个 没有方法类型呢?? 可以让流程设计器加上)
            Boolean hasFlowRecallFunc = properties.getHasFlowRecallFunc();
            userTaskNodeEventDTO.setHasStartActivityWithdrawEventEnable(hasFlowRecallFunc);
            if(hasFlowRecallFunc!=null &&hasFlowRecallFunc){
                String flowRecallInterfaceUrl = properties.getFlowRecallInterfaceUrl();
                userTaskNodeEventDTO.setStartActivityWithdrawEventURL(flowRecallInterfaceUrl);
            }
            //开始事件
            Boolean hasInitfunc = properties.getHasInitfunc();
            userTaskNodeEventDTO.setHasStartActivityStartEventEnable(hasInitfunc);
            if(hasInitfunc!=null&&hasInitfunc){
                String initInterfaceType = properties.getInitInterfaceType();
                String initInterfaceUrl = properties.getInitInterfaceUrl();
                userTaskNodeEventDTO.setStartActivityStartEventInterfaceType(initInterfaceType);
                userTaskNodeEventDTO.setStartActivityStartEventURL(initInterfaceUrl);
            }
            //结束事件
            Boolean hasEndfunc = properties.getHasEndfunc();
            userTaskNodeEventDTO.setHasStartActivityEndEventEnable(hasEndfunc);
            if(hasEndfunc!=null &&hasEndfunc){
                String endInterfaceType = properties.getEndInterfaceType();
                String endInterfaceUrl = properties.getEndInterfaceUrl();
                userTaskNodeEventDTO.setStartActivityEndEventInterfaceType(endInterfaceType);
                userTaskNodeEventDTO.setStartActivityEndEventURL(endInterfaceUrl);
            }
        }
        //正常的审批节点
        else{
            //1.1 流程设计器节点 4个tab页之1 -->审批人tab页信息设置
            //判断是否是会签(或签 & 并签)
            String assigneeType = properties.getAssigneeType();
            //
            Integer counterSign = properties.getCounterSign();
            Long countersignRatio = properties.getCountersignRatio();


            List<String> approverPos = properties.getApproverPos();
            List<String> approvers = properties.getApprovers();
            List<String> approverRole = properties.getApproverRole();
            if(approverPos!=null){
                userTaskBasicPropDTO.setApproverPos(approverPos);
            }
            if(approvers!=null){
                userTaskBasicPropDTO.setApprovers(approvers);
            }
            if(approverRole!=null){
                userTaskBasicPropDTO.setApproverRole(approverRole);
            }

            //发起人本人 3 单个人
            if(FlowTaskOperatorEnum.InitiatorMe.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
            }
            /**
             * 变量 4  多个人->候选人
             * 虽然这个在流程设计器上面可以选择
             *  但是它的解释: 将由流程表单中的人员进行审批
             *  那么 流程表单中的人员  这个词汇 该去怎么定义呢??
             *  拖拽表单设计器上并没有 一个专门的控件叫做  审批人员控件  所以 没办法做到统一的话
             *  到时候 设置真正的人时候 就没法取真实的值
             */
            else if(FlowTaskOperatorEnum.Variate.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
                userTaskBasicPropDTO.setFormField(properties.getFormField());
            }
            //发起者主管 1  单个人
            else if(FlowTaskOperatorEnum.LaunchCharge.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
                userTaskBasicPropDTO.setManagerLevel(properties.getManagerLevel());
            }
            //部门主管 2    单个人
            else if(FlowTaskOperatorEnum.DepartmentCharge.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
            }
            //环节 5 多个人 会签节点??算了
            else if(FlowTaskOperatorEnum.Tache.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
                userTaskBasicPropDTO.setNodeId(properties.getNodeId());
            }
            //指定成员 6 多个人 会签节点
            else if(FlowTaskOperatorEnum.Nominator.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
                //设置会签信息
                setCounterSignInfo(userTask,counterSign,countersignRatio);
            }
            //服务  9 多个人 会签节点
            else if(FlowTaskOperatorEnum.Serve.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
                userTaskBasicPropDTO.setGetUserUrl(properties.getGetUserUrl());
                //设置会签信息
                setCounterSignInfo(userTask,counterSign,countersignRatio);
            }
            //候选人员 官方新版已经支持
            else if(FlowTaskOperatorEnum.CandidateUser.getCode().equals(assigneeType)){
                userTaskBasicPropDTO.setAssigneeType(assigneeType);
            }
            else{
                log.error("暂不支持此类型选人方式");
                throw new ActivitiWorkFlowException("暂不支持此类型选人方式");
            }

            //是否允许加签
            Boolean hasFreeApprover = properties.getHasFreeApprover();
            userTaskBasicPropDTO.setHasFreeApprover(hasFreeApprover);


            //进度选择
            String progress = properties.getProgress();
            if(StringUtils.isNotBlank(progress)){
                userTaskBasicPropDTO.setProgress(progress);
            }
            //1.2 流程设计器节点 4个tab页之2 -->抄送人tab页信息设置
            List<String> circulateRole = properties.getCirculateRole();
            if(circulateRole!=null &&!circulateRole.isEmpty()){
                userTaskBasicPropDTO.setCirculateRole(circulateRole);
            }

            List<String> circulatePosition = properties.getCirculatePosition();
            if(circulatePosition!=null && !circulatePosition.isEmpty()){
                userTaskBasicPropDTO.setCirculatePosition(circulatePosition);
            }
            List<String> circulateUser = properties.getCirculateUser();
            if(circulateUser!=null && !circulateUser.isEmpty()){
                userTaskBasicPropDTO.setCirculateUser(circulateUser);
            }

            //自定义抄送人
            Boolean isCustomCopy = properties.getIsCustomCopy();
            userTaskBasicPropDTO.setIsCustomCopy(isCustomCopy);

            ////////////////////////高级设置配置页//////////////////////////////
            Boolean hasAuditBtn = properties.getHasAuditBtn();
            String auditBtnText = properties.getAuditBtnText();
            userTaskAdvancedSettingDTO.setHasAuditBtn(hasAuditBtn);
            if(StringUtils.isBlank(auditBtnText)){
                auditBtnText="通过";
                userTaskAdvancedSettingDTO.setAuditBtnText(auditBtnText);
            }
            Boolean hasRejectBtn = properties.getHasRejectBtn();
            String rejectBtnText = properties.getRejectBtnText();
            userTaskAdvancedSettingDTO.setHasRejectBtn(hasRejectBtn);
            if(StringUtils.isBlank(rejectBtnText)){
                rejectBtnText="拒绝";
                userTaskAdvancedSettingDTO.setRejectBtnText(rejectBtnText);
            }
            Boolean hasRevokeBtn = properties.getHasRevokeBtn();
            userTaskAdvancedSettingDTO.setHasRevokeBtn(hasRevokeBtn);
            String revokeBtnText = properties.getRevokeBtnText();
            if(StringUtils.isBlank(revokeBtnText)){
                revokeBtnText="撤回";
                userTaskAdvancedSettingDTO.setRevokeBtnText(revokeBtnText);
            }
            Boolean hasTransferBtn = properties.getHasTransferBtn();
            String transferBtnText = properties.getTransferBtnText();
            if(StringUtils.isBlank(transferBtnText)){
                transferBtnText="转办";
                userTaskAdvancedSettingDTO.setTransferBtnText(transferBtnText);
            }

            Boolean hasSign = properties.getHasSign();
            userTaskAdvancedSettingDTO.setHasSign(hasSign);

            //超时设置
            TimeOutConfig timeoutConfig = properties.getTimeoutConfig();
            if(timeoutConfig!=null){
                userTaskAdvancedSettingDTO.setTimeOutConfig(timeoutConfig);
            }
            //跳过策略


            //驳回步骤
            String rejectStep = properties.getRejectStep();
            if(StringUtils.isNotBlank(rejectStep)){
                userTaskAdvancedSettingDTO.setRejectStep(rejectStep);
            }

            //通知设置
            List<String> messageType = properties.getMessageType();
            userTaskAdvancedSettingDTO.setMessageType(messageType);
            //说明
            String description = properties.getDescription();
            userTaskAdvancedSettingDTO.setDescription(description);



            //1.4 流程设计器节点 4个tab页之4 -->
            // 节点的审批事件
            Boolean hasApproverfunc = properties.getHasApproverfunc();
            userTaskNodeEventDTO.setHasActivityApprovalEventEnable(hasApproverfunc);
            if(hasApproverfunc!=null&&hasApproverfunc){
                String approverInterfaceType = properties.getApproverInterfaceType();
                String approverInterfaceUrl = properties.getApproverInterfaceUrl();
                userTaskNodeEventDTO.setActivityApprovalEventInterfaceType(approverInterfaceType);
                userTaskNodeEventDTO.setActivityApprovalEventURL(approverInterfaceUrl);
            }
            //节点撤回事件
            Boolean hasRecallFunc = properties.getHasRecallFunc();
            userTaskNodeEventDTO.setHasActivityWithdrawEventEnable(hasApproverfunc);
            if(hasRecallFunc!=null && hasRecallFunc){
                String recallInterfaceUrl = properties.getRecallInterfaceUrl();
                userTaskNodeEventDTO.setActivityWithdrawEventURL(recallInterfaceUrl);
            }
        }
        //1.3 流程设计器节点 发起节点和 审批节点都有这个tab页 -->表单权限信息设置
        List<FormOperates> formOperates = properties.getFormOperates();
        if(formOperates!=null &&!formOperates.isEmpty()){
            activityExPropertyDTO.setOperatesList(formOperates);
        }

        activityExPropertyDTO.setUserTaskBasicPropDTO(userTaskBasicPropDTO);
        activityExPropertyDTO.setUserTaskAdvancedSettingDTO(userTaskAdvancedSettingDTO);
        activityExPropertyDTO.setUserTaskNodeEventDTO(userTaskNodeEventDTO);
        //1.3.1添加扩展属性
        extensionAttribute.setValue(JSONObject.toJSONString(activityExPropertyDTO));
        //1.3.2 将扩展属性添加到userTask对象中
        userTask.addAttribute(extensionAttribute);
        //1.4 流程事件 上述逻辑中已经设置了
        process.addFlowElement(userTask);
        return userTaskId;
    }

    /**
     * 创建调用活动
     */
    public static String createCallActivity(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        CallActivity callActivity=new CallActivity();
        callActivity.setId(childNode.getNodeId());
        callActivity.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        callActivity.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());
        //业务key
        String flowId = childNode.getProperties().getFlowId();
        CallActivityExPropertyDTO callActivityExPropertyDTO=new CallActivityExPropertyDTO();

        FlowEngineService flowEngineService = SpringContextHolder.getBean(FlowEngineService.class);
        FlowEngineEntity flowEngineEntity = flowEngineService.getById(flowId);
        String enCode = flowEngineEntity.getEnCode();
        String processDefinitionKey=BasicActivitiConstants.activitiPrefix+enCode;
        //调用的另一个流程定义key
        callActivity.setCalledElement(processDefinitionKey);
        callActivity.setCalledElementType(CALLED_ELEMENT_TYPE_KEY);
        //是否继承主流程的业务key 不应该继承
        callActivity.setInheritBusinessKey(false);
        //
        FlowableListener flowableListener = new FlowableListener();
        flowableListener.setEvent(ExecutionListener.EVENTNAME_START);
        flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
        flowableListener.setImplementation("#{callActivityStartedListener}");

        List<FlowableListener> flowableListenerList=new ArrayList<>();
        flowableListenerList.add(flowableListener);
        callActivity.setExecutionListeners(flowableListenerList);
        List<FlowAssignModel> assignList = properties.getAssignList();

        List<String> parentFields=new ArrayList<>();
        List<String> subFields=new ArrayList<>();
        List<IOParameter> ioParameterList=new ArrayList<>();
        for (FlowAssignModel flowAssignModel : assignList) {
           IOParameter ioParameter=new IOParameter();
           ioParameter.setSource(flowAssignModel.getParentField());
           ioParameter.setTarget(flowAssignModel.getChildField());
           ioParameterList.add(ioParameter);
        }
        //输入参数
        callActivity.setInParameters(ioParameterList);
        //输出参数
//        callActivity.setOutParameters(ioParameterList);
        callActivityExPropertyDTO.setMessageType(properties.getMessageType());
        callActivityExPropertyDTO.setAssignList(assignList);
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        //1.3.1添加扩展属性
        extensionAttribute.setValue(JSONObject.toJSONString(callActivityExPropertyDTO));
        //1.3.2 将扩展属性添加到userTask对象中
        callActivity.addAttribute(extensionAttribute);
        //1.4 流程事件 上述逻辑中已经设置了
        process.addFlowElement(callActivity);
        return callActivity.getId();
    }

    /**
     * 创建抄送节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createManualTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ManualTask manualTask=new ManualTask();
        manualTask.setId(childNode.getNodeId());
        manualTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        manualTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());



        List<String> circulatePosition = properties.getCirculatePosition();
        List<String> circulateRole = properties.getCirculateRole();
        List<String> circulateUser = properties.getCirculateUser();
        List<String> to = properties.getTo();
        String from = properties.getFrom();
        String subject = properties.getSubject();
        List<String> cc = properties.getCc();
        List<String> bcc = properties.getBcc();
        String html = properties.getHtml();
        Boolean processFlag = properties.getProcessFlag();
        String notifyContent = properties.getNotifyContent();


        String type = childNode.getType();
        ManualTaskExPropertyDTO manualTaskExPropertyDTO=new ManualTaskExPropertyDTO();
        manualTaskExPropertyDTO.setType(childNode.getType());
        //如果是抄送节点
        if(FlowNodeTypeEnum.COPY.getType().equals(type)){
            //作为抄送节点时需要设置的值--start
            manualTaskExPropertyDTO.setCirculatePosition(circulatePosition);
            manualTaskExPropertyDTO.setCirculateRole(circulateRole);
            manualTaskExPropertyDTO.setCirculateUser(circulateUser);
            //作为抄送节点时需要设置的值--end
        }
        //如果是邮件节点
        else if(FlowNodeTypeEnum.MAIL.getType().equals(type)){
            //作为邮件节点时--start
            manualTaskExPropertyDTO.setTo(to);
            manualTaskExPropertyDTO.setFrom(from);
            manualTaskExPropertyDTO.setCc(cc);
            manualTaskExPropertyDTO.setBcc(bcc);
            manualTaskExPropertyDTO.setHtml(html);
            manualTaskExPropertyDTO.setSubject(subject);
            //邮件附件列表
            manualTaskExPropertyDTO.setMailFiles(properties.getFileList());
            //作为邮件节点时--end
        }
        //作为发送钉钉\站内信\微信\短信时:
        else if(FlowNodeTypeEnum.DING.getType().equals(type)
        || FlowNodeTypeEnum.WX.getType().equals(type)
        || FlowNodeTypeEnum.DX.getType().equals(type)
        || FlowNodeTypeEnum.ZHAN.getType().equals(type)
        ){
            manualTaskExPropertyDTO.setTo(to);
            manualTaskExPropertyDTO.setProcessFlag(processFlag);
            manualTaskExPropertyDTO.setNotifyContent(notifyContent);
        }
        //其他类型的报错
        else{
            throw new WorkFlowException("不支持此类型的节点");
        }

        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        //1.3.1添加扩展属性
        extensionAttribute.setValue(JSONObject.toJSONString(manualTaskExPropertyDTO));
        //1.3.2 将扩展属性添加到userTask对象中
        manualTask.addAttribute(extensionAttribute);
        //1.4 流程事件 上述逻辑中已经设置了
        process.addFlowElement(manualTask);
        return manualTask.getId();
    }

    /**
     * 创建ServiceTask(业务)节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createServiceTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ServiceTask serviceTask=new ServiceTask();
        serviceTask.setId(childNode.getNodeId());
        serviceTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        serviceTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());

        String serviceClassName = properties.getServiceClassName();

        serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS);
        Class<?> aClass=null;
        try {
            aClass = Thread.currentThread().getContextClassLoader().loadClass(serviceClassName);
        } catch (ClassNotFoundException e) {
            throw new WorkFlowException("请提供本系统中有效的类,并且此类需要继承JavaDelegate或者ActivityBehavior的Java类");
        }
        Class<?>[] interfaces = aClass.getInterfaces();
        List<Class<?>> classes = Arrays.asList(interfaces);
        if(!classes.contains(JavaDelegate.class) || !classes.contains(ActivityBehavior.class)){
            throw new WorkFlowException("请提供本系统中有效的类,并且此类需要继承JavaDelegate或者ActivityBehavior的Java类");
        }
        //实现类
        serviceTask.setImplementation(serviceClassName);
        process.addFlowElement(serviceTask);
        return serviceTask.getId();
    }


    /**
     * 创建ServiceTask(业务)节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createScriptTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ScriptTask scriptTask=new ScriptTask();
        scriptTask.setId(childNode.getNodeId());
        scriptTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        scriptTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());

        Integer scriptFormat = properties.getScriptFormat();
        String scriptContent = properties.getScriptContent();
        scriptTask.setScriptFormat(FlowScriptTypeEnum.getMessageByIndex(scriptFormat));

        //如果是groovy 需要校验groovy语法是否正确
        if(scriptFormat==1){
            boolean b = grammarCheck(scriptContent);
            if(!b){
                throw  new WorkFlowException("编写的Groovy脚本有问题,请重试");
            }
        }
        scriptTask.setScript(scriptContent);
        process.addFlowElement(scriptTask);
        return scriptTask.getId();
    }

    /**
     * 创建ServiceTask(业务)节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createShellTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ServiceTask serviceTask=new ServiceTask();
        serviceTask.setId(childNode.getNodeId());
        serviceTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        serviceTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());

        //脚本类型任务
        serviceTask.setType("shell");

        String shellCommand = properties.getShellCommand();
//        String arg1 = properties.getArg1();
//        String arg2 = properties.getArg2();
//        String arg3 = properties.getArg3();
//        String arg4 = properties.getArg4();
//        String arg5 = properties.getArg5();

        List<FieldExtension> fieldExtensionList=new ArrayList<>();
        //shell->命令
        if(StringUtils.isNotBlank(shellCommand)){
            FieldExtension commandExtension=new FieldExtension();
            commandExtension.setFieldName("command");
            commandExtension.setStringValue(shellCommand);
            fieldExtensionList.add(commandExtension);
        }
        //
//        if(StringUtils.isNotBlank(arg1)){
//            FieldExtension commandExtension=new FieldExtension();
//            commandExtension.setFieldName("arg1");
//            commandExtension.setStringValue(arg1);
//            fieldExtensionList.add(commandExtension);
//        }
//        if(StringUtils.isNotBlank(arg2)){
//            FieldExtension commandExtension=new FieldExtension();
//            commandExtension.setFieldName("arg2");
//            commandExtension.setStringValue(arg2);
//            fieldExtensionList.add(commandExtension);
//        }
//        if(StringUtils.isNotBlank(arg3)){
//            FieldExtension commandExtension=new FieldExtension();
//            commandExtension.setFieldName("arg3");
//            commandExtension.setStringValue(arg3);
//            fieldExtensionList.add(commandExtension);
//        }
//        if(StringUtils.isNotBlank(arg4)){
//            FieldExtension commandExtension=new FieldExtension();
//            commandExtension.setFieldName("arg4");
//            commandExtension.setStringValue(arg4);
//            fieldExtensionList.add(commandExtension);
//        }
//        if(StringUtils.isNotBlank(arg5)){
//            FieldExtension commandExtension=new FieldExtension();
//            commandExtension.setFieldName("arg5");
//            commandExtension.setStringValue(arg5);
//            fieldExtensionList.add(commandExtension);
//        }

        Boolean waitShellFlag = properties.getWaitShellFlag();
        if(waitShellFlag){
            FieldExtension commandExtension=new FieldExtension();
            commandExtension.setFieldName("wait");
            commandExtension.setStringValue(waitShellFlag+"");
            fieldExtensionList.add(commandExtension);
        }

        String shellDirectory = properties.getShellDirectory();
        if(StringUtils.isNotBlank(shellDirectory)){
            FieldExtension commandExtension=new FieldExtension();
            commandExtension.setFieldName("directory");
            commandExtension.setStringValue(shellDirectory);
            fieldExtensionList.add(commandExtension);
        }
        serviceTask.setFieldExtensions(fieldExtensionList);
        process.addFlowElement(serviceTask);
        return serviceTask.getId();
    }


    /**
     * 创建ServiceTask(业务)节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createHttpServiceTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        HttpServiceTask httpServiceTask=new HttpServiceTask();
        httpServiceTask.setId(childNode.getNodeId());
        httpServiceTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        httpServiceTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());

        Integer requestMethodCode = properties.getRequestMethodCode();
        String requestURL = properties.getRequestURL();
//        String requestHeaders = properties.getRequestHeaders();
//        requestHeaders = requestHeaders.replaceAll(";", "\n");
        String requestBody = properties.getRequestBody();
        Integer requestConnectionTimeOut = properties.getRequestConnectionTimeOut();

        List<FieldExtension> fieldExtensionList=new ArrayList<>();
        FieldExtension methodExtension=new FieldExtension();
        methodExtension.setFieldName("requestMethod");
        methodExtension.setStringValue(FlowRequestMethodEnum.getMessageByIndex(requestMethodCode));
        fieldExtensionList.add(methodExtension);

 /*       FieldExtension requestHeaderExtension=new FieldExtension();
        requestHeaderExtension.setFieldName("requestHeaders");
        requestHeaderExtension.setStringValue(requestHeaders);
        fieldExtensionList.add(requestHeaderExtension);*/

        FieldExtension requestBodyExtension=new FieldExtension();
        requestBodyExtension.setFieldName("requestBody");
        boolean json = isJSON(requestBody);
        if (json) {
            requestBodyExtension.setStringValue(requestBody);
        }
        else{
            throw new WorkFlowException("请求体数据必须是JSON格式");
        }

        fieldExtensionList.add(requestBodyExtension);

        FieldExtension requestUrlExtension=new FieldExtension();
        requestUrlExtension.setFieldName("requestUrl");
        if(isURL(requestURL)){
            requestUrlExtension.setStringValue(requestURL);
        }
        else{
            throw new WorkFlowException("请求的URL格式错误,请检查之后再试");
        }
        fieldExtensionList.add(requestUrlExtension);


        FieldExtension requestTimeOutExtension=new FieldExtension();
        requestTimeOutExtension.setFieldName("requestTimeout");
        requestTimeOutExtension.setStringValue(requestConnectionTimeOut+"");
        fieldExtensionList.add(requestTimeOutExtension);

        httpServiceTask.setFieldExtensions(fieldExtensionList);
        process.addFlowElement(httpServiceTask);
        return httpServiceTask.getId();
    }

    /**
     * 校验是不是groovy语法
     * @return
     */
    public static boolean grammarCheck(String exp) {
        try {
            new GroovyShell().parse(exp);
            return true;
        } catch(MultipleCompilationErrorsException cfe) {
            return false;
        }
    }

    public static boolean isURL(String str){
        //转换为小写
        str = str.toLowerCase();
        String regex = "^((https|http|ftp|rtsp|mms)?://)" //https、http、ftp、rtsp、mms
                + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" //ftp的user@
                + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如：199.194.52.184
                + "|" // 允许IP和DOMAIN(域名)
                + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www.
                + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名
                + "[a-z]{2,6})" // first level domain- .com or .museum
                + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数
                + "((/?)|" // a slash isn‘t required if there is no file name
                + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$";
        return str.matches(regex);
    }

    /**
     * 判断字符串是不是JSON
     * @param str
     * @return
     */
    public static boolean isJSON(String str) {
        boolean result = false;
        try {
            Object obj= JSON.parse(str);
            result = true;
        } catch (Exception e) {
            result=false;
        }
        return result;
    }


    /**
     * 创建排他网关
     */
    public static ExclusiveGateway createExclusiveGateway(){
        ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
        exclusiveGateway.setId(getId("exclusiveGateway",""));
//        exclusiveGateway.setDefaultFlow(assembleDTO.getDefaultFlowId());
        return exclusiveGateway;
    }

    /**
     * 创建并行网关
     */
    public static ParallelGateway createParallelGateway(){
        ParallelGateway parallelGateway= new ParallelGateway();
        parallelGateway.setId(getId("parallelGateway",""));
        return parallelGateway;
    }

    /**
     * 创建并行网关的开始
     * @return
     */
    public static  ParallelGateway createParallelStartGateway(){
        ParallelGateway parallelGateway = new ParallelGateway();
        parallelGateway.setId(getId("parallelGateway-start",""));
        return parallelGateway;
    }

    /**
     * 创建并行网关的开始
     * @return
     */
    public static  ParallelGateway createParallelStartGatewayWithNodeId(String nodeId){
        ParallelGateway parallelGateway = new ParallelGateway();
        parallelGateway.setId(getId("parallelGateway-start",nodeId));
        return parallelGateway;
    }

    /**
     * 创建并行网关的结束
     * @return
     */
    public static ParallelGateway createParallelEndGateway(){
        ParallelGateway parallelGateway = new ParallelGateway();
        parallelGateway.setId(getId("parallelGateway-end",""));
        return parallelGateway;
    }

    /**
     * 创建并行网关的结束
     * @return
     */
    public static ParallelGateway createParallelEndGatewayWithNodeId(String nodeId){
        ParallelGateway parallelGateway = new ParallelGateway();
        parallelGateway.setId(getId("parallelGateway-end",nodeId));
        return parallelGateway;
    }


    /**
     * 创建包容网关
     */
    public static InclusiveGateway createInclusiveGateway(String nodeId,String nodeName,String document){
        InclusiveGateway inclusiveGateway = new InclusiveGateway();
        inclusiveGateway.setId(nodeId);
        inclusiveGateway.setName(nodeName);
        inclusiveGateway.setDocumentation(document);
        return inclusiveGateway;
    }
    /**
     * 创建ServiceTask  ServiceTask 可以用于 抄送节点 但不是很合适
     * 可以使用ManualTask 来做 这个任务非常适合
     */
    public static ServiceTask createServiceTask(String nodeId,String nodeName,String document){
        ServiceTask serviceTask = new ServiceTask();
        serviceTask.setId(nodeId);
        serviceTask.setName(nodeName);
        serviceTask.setDocumentation(document);
//        serviceTask.setImplementationType(StencilConstants.PROPERTY_SERVICETASK_CLASS);
//        serviceTask.setImplementation();
        return serviceTask;
    }

    /**
     * 创建接收任务  -->可以用作 流程图中的定时器   搭配定时任务使用 就能达到定时器效果
     * 或者搭配zookeeper临时节点也是可以的 搭配redis expires key也可以
     * @param childNode
     * @param process
     * @return
     */
    public static  String createReceiveTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
            ReceiveTask receiveTask = new ReceiveTask();
            Properties properties = childNode.getProperties();
            receiveTask.setId(childNode.getNodeId());
            receiveTask.setName(properties.getTitle());
            receiveTask.setDocumentation(properties.getDescription());
            Integer day = properties.getDay();
            Integer hour = properties.getHour();
            Integer minute = properties.getMinute();
            Integer second = properties.getSecond();
            Integer totalSecond=day*24*60*60;
            totalSecond+=hour*60*60;
            totalSecond+=minute*60;
            totalSecond+=second;
            ExtensionAttribute extensionAttribute = new ExtensionAttribute();
            //扩展属性的JSON值 直接使用JSON来存取 不然的话 需要在XML中定义太多扩展属性了()
            ReceiveTaskExPropertyDTO activityExPropertyDTO =new ReceiveTaskExPropertyDTO();
            extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
            extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
            extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
            activityExPropertyDTO.setTotalSeconds(totalSecond);
            extensionAttribute.setValue(JSONObject.toJSONString(activityExPropertyDTO));
            receiveTask.addAttribute(extensionAttribute);
            process.addFlowElement(receiveTask);
            return receiveTask.getId();
    }


    /**
     * 创建结束事件
     */
    public static EndEvent createEndEvent(){
        EndEvent  endEvent = new EndEvent();
        endEvent.setId(BasicActivitiConstants.endEventId);
        endEvent.setName("流程结束");
        endEvent.setDocumentation("流程结束");
        return endEvent;
    }

    /**
     * 添加一条入线
     * @param source
     * @param incomingFlow
     */
    public static  void addInComingFlow(FlowElement source,SequenceFlow incomingFlow){
        List<SequenceFlow> sequenceFlows = null;
        if (source instanceof Task) {
            sequenceFlows = ((Task) source).getIncomingFlows();
        } else if (source instanceof Gateway) {
            sequenceFlows = ((Gateway) source).getIncomingFlows();
        } else if (source instanceof SubProcess) {
            sequenceFlows = ((SubProcess) source).getIncomingFlows();
        } else if (source instanceof StartEvent) {
            sequenceFlows = ((StartEvent) source).getIncomingFlows();
        } else if (source instanceof EndEvent) {
            sequenceFlows = ((EndEvent) source).getIncomingFlows();
        }
        //
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            if(incomingFlow.getId().equals(sequenceFlow.getId())){
                continue;
            }
            sequenceFlows.add(sequenceFlow);
        }
    }

    /**
     * 添加一条出线
     * @param source
     * @param outgoingFlow
     */
    public static void addOutgoingFlow(FlowElement source,SequenceFlow outgoingFlow) {
        List<SequenceFlow> sequenceFlows = null;
        if (source instanceof Task) {
            sequenceFlows = ((Task) source).getOutgoingFlows();
        } else if (source instanceof Gateway) {
            sequenceFlows = ((Gateway) source).getOutgoingFlows();
        } else if (source instanceof SubProcess) {
            sequenceFlows = ((SubProcess) source).getOutgoingFlows();
        } else if (source instanceof StartEvent) {
            sequenceFlows = ((StartEvent) source).getOutgoingFlows();
        } else if (source instanceof EndEvent) {
            sequenceFlows = ((EndEvent) source).getOutgoingFlows();
        }
        //
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            if(outgoingFlow.getId().equals(sequenceFlow.getId())){
                continue;
            }
            sequenceFlows.add(sequenceFlow);
        }
    }

    /**
     *
     * @param id
     */
    public <T extends FlowElement>FlowElement getFlowElement(String id, Process process){
        FlowElement source = process.getFlowElement(id);
        if (source instanceof Task) {
            source = ((Task) source);
        } else if (source instanceof Gateway) {
            source = ((Gateway) source);
        } else if (source instanceof SubProcess) {
            source = ((SubProcess) source);
        } else if (source instanceof StartEvent) {
            source = ((StartEvent) source);
        } else if (source instanceof EndEvent) {
            source = ((EndEvent) source);
        }
        return source;
    }

    /**
     *
     * @param type  节点类型
     * @param nodeId 自带的节点id
     * @return 节点唯一的ID
     */
    public static String getId(String type,String nodeId){
        if(StringUtils.isNotBlank(nodeId)){
            return type+"-"+nodeId;/*+"-"+ SpringContextHolder.getBean(IdWorker.class).nextId();*/
        }
        else{
            return type+"-"+ SpringContextHolder.getBean(IdWorker.class).nextId();
        }
    }

    public Boolean isMultiInstance(FlowElement flowElement){
        if(flowElement instanceof UserTask){
            UserTask userTask=(UserTask)flowElement;
            return userTask.hasMultiInstanceLoopCharacteristics();
        }
        else{
            return false;
        }
    }

    public static Process getBpmnModelMainProcess(String processDefinitionId){
        RepositoryServiceImpl repositoryService = SpringContextHolder.getBean(RepositoryServiceImpl.class);
        return repositoryService.getBpmnModel(processDefinitionId).getMainProcess();
    }

    public static String getAttributeValueByTaskDefinitionKey(Process process,String taskDefinitionKey,String nodeType){
        FlowElement flowElement = process.getFlowElement(taskDefinitionKey);
        if("userTask".equals(nodeType)){
            UserTask userTask=(UserTask)flowElement;
            String property = userTask.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            return property;
        }
        else if("receiveTask".equals(nodeType)){
            ReceiveTask receiveTask=(ReceiveTask)flowElement;
            String property = receiveTask.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            return property;
        }
        else if("manualTask".equals(nodeType)){
            ManualTask manualTask=(ManualTask)flowElement;
            String property = manualTask.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            return property;
        }
        else if("callActivity".equals(nodeType)){
            CallActivity callActivity=(CallActivity)flowElement;
            String property = callActivity.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            return property;

        }
        else if("global".equals(nodeType)){
            String property = process.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            return property;
        }
        return null;
    }

    /**
     * 在本系统中starEvent必定只有一条连线且 目标节点必定是userTask
     * @param process
     * @return
     */
    public static UserTask getFirstNode(Process process){
        return (UserTask)((StartEvent)process.getInitialFlowElement()).getOutgoingFlows().get(0).getTargetFlowElement();
    }

    /**
     * 获取Process中 除了连线的元素
     * @param process
     * @return
     */
    public static List<FlowElement> getFlowElementsWithOutSequenceFlow(Process process){
        List<FlowElement> finalElements=new ArrayList<>();
        Collection<FlowElement> flowElements = process.getFlowElements();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow){

            }
            else{
               finalElements.add(flowElement);
            }
        }
        return finalElements;
    }

    public static FlowNode getFlowNodeById(Process process,String nodeId){
            return (FlowNode) process.getFlowElement(nodeId);
    }
}
