<template>
    <div>
      <button @mousedown="startDrag('Start', $event)">开始节点</button>
      <button @mousedown="startDrag('End', $event)">结束节点</button>
      <button @mousedown="startDrag('Circle', $event)">循环节点</button>
      <button @mousedown="startDrag('Rect', $event)">任务节点</button>
      <button @mousedown="startDrag('polygon', $event)">条件节点</button>
      <button @click="deleteNode()">删除</button>
      <button @click="onUndo">撤销</button>
      <button @click="onRedo">重做</button>
      <button @click="savePic">生成图片</button>
      <button @click="saveFlow">保存流程图并生成java代码</button>
      <button @click="getJson">getJson</button>
      <div class="graph-drawer-box">
        <div ref="graphContainer"></div>
        <RightDrawer ref="rightDrawer"
          :drawerType="type" :selectCellNum="selectCellNum" :selectCell="selectCell" 
          :graph="graph" :grid="grid" @deleteNode="deleteNode"></RightDrawer>
      </div>
    </div>
  </template>
  <script>
  import { Graph, Shape, FunctionExt, DataUri } from '@antv/x6';
  // import insertCss from 'insert-css';
  // 添加 Dnd 导入
import { Dnd } from '@antv/x6-plugin-dnd';
  import data from './nodes/data.js'
  import { startDragToGraph } from './nodes/methods.js';
  import RightDrawer from './nodes/right-drawer';
  export default {
    name: 'index2Page',
    components: {
      RightDrawer
    },
    data() {
      return {
        selectCellNum: 0,
        contentWidth: 0,
        contentHeight: 0,
        graph: null,
        type: 'grid',
        selectCell: '',
        connectEdgeType: {  //连线方式
          connector: 'normal',
          router: {
            // name: ''
            name: 'normal'
          }
        },
        grid: { // 网格设置
          showGrid: true,
          size: 10,      // 网格大小 10px
          visible: true, // 渲染网格背景
          type: 'mesh',
          args: {
            color: '#D0D0D0',
            thickness: 1,     // 网格线宽度/网格点大小
            factor: 10,
          },
        },
        canUndo: false,
        canRedo: false,
        haveStart: false,  //已有开始或结束
        haveEnd: false,
      }
    },
    mounted() {
      // 在初始化图形之前注册插件
      Graph.use(['dnd']);
      this.initX6()
    },
    methods: {
      // initGraph() {
      //   this.graph = new Graph({
      //     container: document.getElementById('container'),
      //     width: 800,
      //     height: 600,
      //     background: {
      //       color: '#F2F7FA'
      //     }
      //   })
      //   console.log(dataJSON)
      //   this.graph.fromJSON(dataJSON) // 渲染元素　　　 this.graph.centerContent() // 居中显示
      // },
      // 计算main主体高度
      getMainHeight(e) {
        /* this.contentHeight = Math.max(window.innerHeight - 60, 400);
        this.contentWidth = window.innerWidth - 250;
        if (e) {
          //画布调整大小
          this.graph.resize(this.contentWidth, this.contentHeight);
        } */
        this.contentWidth = this.$refs['graphContainer'].parentNode.offsetWidth;
        this.contentHeight = 910;
      },
      initX6() {
        this.type = 'grid';
        this.selectCell = '';
        let _that = this;
        // window.addEventListener('resize', this.debounceHeight);
        this.graph = new Graph({
          container: this.$refs['graphContainer'],
          width: 1200,
          height: 600,
          grid: this.grid,
          panning: {
            enabled: true,
            modifiers: 'shift'
          }, //平移
          resizing: { //调整节点宽高
            enabled: true,
            orthogonal: false,
          },
          selecting: true, //可选
          snapline: true,
          interacting: {
            edgeLabelMovable: true
          },
          connecting: { // 节点连接
            anchor: 'center',
            connectionPoint: 'anchor',
            allowBlank: false,
            snap: true,
            createEdge() {
              return new Shape.Edge({
                attrs: {
                  line: {
                    stroke: '#1890ff',
                    strokeWidth: 1,
                    targetMarker: {
                      name: 'classic',
                      size: 8
                    },
                    strokeDasharray: 0, //虚线
                    style: {
                      animation: 'ant-line 30s infinite linear',
                    },
                  },
                },
                label: {
                  text: ''
                },
                connector: _that.connectEdgeType.connector,
                router: {
                  name: _that.connectEdgeType.router.name || ''
                },
                zIndex: 0
              })
            },
          },
          highlighting: {
            magnetAvailable: {
              name: 'stroke',
              args: {
                padding: 4,
                attrs: {
                  strokeWidth: 4,
                  stroke: '#6a6c8a'
                }
              }
            }
          },
          //滚动
          scroller: {
            enabled: false
          },
          //小地图
          minimap: {
            enabled: !this.readonly,
            container: !this.readonly ? this.$refs['rightDrawer'].$refs['miniMap'] : '',
            width: 300,
            height: 150,
            padding: 5
          },
          //缩放
          mousewheel: {
            enabled: true,
            modifiers: ['ctrl', 'meta'],
          },
          // 历史
          history: {
            enabled: true,
          },
          //框选
          selecting: {
            enabled: true,
            rubberband: true
          },
        });
        // insertCss(`
        //         @keyframes ant-line {
        //           to {
        //               stroke-dashoffset: -1000
        //           }
        //         }
        //       `)
        this.graph.fromJSON(data);
        this.graph.history.redo();
        this.graph.history.undo();
        // 鼠标移入移出节点
        this.graph.on('node:mouseenter', FunctionExt.debounce(() => {
          const container = this.$refs['graphContainer']
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, true)
        }), 500);
        this.graph.on('node:mouseleave', () => {
          const container = this.$refs['graphContainer']
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, false)
        });
        this.graph.on('blank:click', () => {
          this.type = 'grid';
          //选中网格需清空选中节点的数据
          this.selectCell = '';
          console.log('blank:click')
        });
        this.graph.on('cell:click', ({ cell }) => {
          this.type = cell.isNode() ? 'node' : 'edge';
          this.$emit('cellClick', cell);
          console.log('cell:click', cell, cell.isNode(), cell.attrs.nodeData, cell)
        });
        //监听框选
        this.graph.on('selection:changed', args => {
          //记录当前选中的数量
          this.selectCellNum = args.selected.length;
          if (this.selectCellNum > 1) {
            //只有选中一个节点时才允许修改节点信息
            this.type = 'grid';
            this.selectCell = '';
          } else {
            this.selectCell = args.added[0];
          }
          args.added.forEach(cell => {
            // this.selectCell = cell
            if (cell.isEdge()) {
              cell.isEdge() && cell.attr('line/strokeDasharray', 5) //虚线蚂蚁线
              cell.addTools([
                {
                  name: 'vertices',
                  args: {
                    padding: 4,
                    attrs: {
                      strokeWidth: 0.1,
                      stroke: '#2d8cf0',
                      fill: '#ffffff',
                    }
                  },
                },
              ])
            }
          })
          args.removed.forEach(cell => {
            cell.isEdge() && cell.attr('line/strokeDasharray', 0);  //正常线
            cell.removeTools();
          })
        });
        /**
         * 处理history
         */
        //监听撤销
        this.graph.history.on('undo', args => {
          // code here
          this.$emit('historyUndo', args);
        });
        //监听重做
        this.graph.history.on('redo', args => {
          // code here
          this.$emit('historyRedo', args);
        });
        this.graph.history.on('change', () => {
          this.historyChange();
        });
        // 监听节点新增
        this.graph.on('node:added', args => {
          const { cell } = args;
          // 检查禁用情况
          this.checkNode();
          //选中
          this.graph.resetSelection(cell);
          this.type = 'node';
          const data = cell.store.data;
          switch (data.attrs.nodeData.type) {
            case 'Start':
              //开始
              this.haveStart = true;
              break;
            case 'End':
              //结束
              this.haveEnd = true;
              break;
          }
        });
        //监听节点删除
        this.graph.on('node:removed', args => {
          const { cell } = args;
          const data = cell.store.data;
          // 检查禁用情况
          this.checkNode();
          switch (data.attrs.nodeData.type) {
            case 'Start':
              //开始
              this.haveStart = false;
              break;
            case 'End':
              //结束
              this.haveEnd = false;
              break;
          }
        });
        //边连接
        this.graph.on('edge:connected', args => {
          //选中节点
          this.graph.resetSelection(args.edge);
          this.type = 'edge';
          console.log('edge:connected', args.edge)
        })
      },
      showPorts(ports, show) {
        for (let i = 0, len = ports.length; i < len; i = i + 1) {
          ports[i].style.visibility = show ? 'visible' : 'hidden'
        }
      },    // 拖拽生成正方或者圆形
      startDrag(type, e) {
        if (this.disabled) {
          return;
        }
        //只能有一个开始和结束
        if (type === 'Start') {
          if (this.haveStart) {
            return;
          }
        } else if (type === 'End') {
          if (this.haveEnd) {
            return;
          }
        }
        startDragToGraph(this.graph, type, e);
      },
      // 删除节点
      deleteNode() {
        if (this.disabled) {
          return;
        }
        const cell = this.graph.getSelectedCells();
        this.graph.removeCells(cell);
        this.type = 'grid';
      },
      // 保存png
      savePic() {
        this.$nextTick(() => {
          this.graph.toPNG(dataUri => {
            // 下载
            DataUri.downloadDataUri(dataUri, this.title + '.png');
          }, {
            backgroundColor: 'white',
            padding: {
              top: 50,
              right: 50,
              bottom: 50,
              left: 50
            },
            quality: 1,
            copyStyles: false
          })
        })
      },
      /**
       * 检查是否可以禁用关联模型
       * 当节点中存在非开始和结束节点时不允许编辑 
       */ 
       checkNode(checkStartAndEnd) {
        const node = this.graph.getNodes();
        const ignores = ['Start', 'End'];
        let diabledEntity = false;
        console.log('node', node)
        for (let i = node.length - 1; i > -1; i--) {
          if (ignores.indexOf(node[i].attrs.nodeData.type) < 0) {
            diabledEntity = true;
            if (!checkStartAndEnd) {
              break;
            }
          } else if (checkStartAndEnd) {
            if (node[i].attrs.nodeData.type === 'Start') {
              this.haveStart = true;
            } else {
              this.haveEnd = true;
            }
          }
        }
        this.diabledEntity = diabledEntity;
      },
      //流程图完整性校验
      checkFlow() {
        const graphToJson = this.graph.toJSON();
        const { cells } = graphToJson;
        /**
         * 1、完整的流程图必需包含开始节点和结束节点且仅有一个
         * 2、每个节点必定有至少一条与其他节点的连接线；
         * 3、开始节点只能是连接线起点
         * 4、结束节点只能是连接线终点
         */
        let errs = [], //错误消息集合
          nodeList = [],
          edgeList = [],
          startNum = 0,
          endNum = 0,
          len = cells.length,
          alls = [],   //所有节点
          edges = [];  //与其他节点有连接关系的节点集合（不包含自己与自己连接的）
        if (len === 0) {
          errs.push('画布不能为空');
        } else {
          for (let i = 0; i < len; i++) {
            //非连线(节点)
            if (cells[i].shape !== 'edge') {
              //节点数据
              const nodeData = cells[i].attrs.nodeData;
              //节点名称
              const nodeText = cells[i].attrs.label.text;
              const flowNode = nodeData.flowNode;
              if (nodeData.type === 'Start') {
                startNum++;
              } else if (nodeData.type === 'End') {
                endNum++;
              } else if (nodeData.type === 'Rect') {
                let errTxt = '任务节点【' + nodeText + '】';
                switch (flowNode.flowNodeType) {
                  case '':
                    errs.push(errTxt + '未选择节点类型');
                    break;
                  case '2':
                    //执行规则组
                    if (flowNode.groupIdentify === '') {
                      errs.push(errTxt + '未选择执行规则组');
                    }
                    break;
                  case '6':
                    //子流程
                    if (flowNode.childFlowIdentify === '') {
                      errs.push(errTxt + '未选择子流程');
                    }
                    break;
                  case '7':
                    //源码节点
                    if (flowNode.methodName === '') {
                      errs.push(errTxt + '未选择方法');
                    } else if (flowNode.hasMethodParams && flowNode.methodParams === '') {
                      errs.push(errTxt + '方法未输入参数');
                    }
                    break;
                }
              } else if (nodeData.type === 'polygon') {
                const errTxt = '条件节点【' + nodeText + '】';
                //处理条件节点的边
                let conditionEdges = this.graph.getOutgoingEdges(cells[i].id);
                console.log('conditionEdges', conditionEdges)
                if (conditionEdges) {
                  conditionEdges = conditionEdges.filter(item => {
                    return item.source.cell !== item.target.cell;
                  });
                  let trueNum = 0,
                    falseNum = 0;
                  conditionEdges.forEach(item => {
                    console.log('item', item)
                    let labelText = item.store.data.labels ? item.store.data.labels[0].text != undefined ? item.store.data.labels[0].text : item.store.data.labels[0].attrs.label.text : '';
                    if (labelText === '是') {
                      trueNum++;
                    } else if (labelText === '否') {
                      falseNum++;
                    }
                  });
                  if (trueNum < 1) {
                    errs.push(errTxt + '缺少是判断的连线');
                  } else if (trueNum > 1) {
                    errs.push(errTxt + '过多是判断的连线');
                  }
                  if (falseNum < 1) {
                    errs.push(errTxt + '缺少否判断的连线');
                  } else if (falseNum > 1) {
                    errs.push(errTxt + '过多否判断的连线');
                  }
                }
                //校验条件表单
                if (flowNode.flowJudges.length < 1) {
                  errs.push(errTxt + '未选择判断条件');
                }
              }
              alls.push({
                id: cells[i].id,
                type: cells[i].attrs.nodeData.type
              });
              nodeList.push(cells[i]);
            } else {
              //连接线
              if (cells[i].source.cell !== cells[i].target.cell) {
                edges.push({
                  source: cells[i].source.cell,
                  target: cells[i].target.cell
                });
              }
              edgeList.push(cells[i]);
            }
          }
  
          if (startNum !== 1) {
            errs.push('开始节点必需存在，且仅有一个');
          }
          if (endNum !== 1) {
            errs.push('结束节点必需存在，且仅有一个');
          }
  
          let startEdgeErr = false,
            endEdgeErr = false,
            edgeErr = false;
          //遍历所有节点
          alls.forEach(item => {
            let hasEdge = false;
            for (let i = 0, len = edges.length; i < len; i++) {
              if (item.id === edges[i].source || item.id === edges[i].target) {
                hasEdge = true;
              }
              if (item.type === 'Start') {
                if (item.id === edges[i].target && !startEdgeErr) {
                  startEdgeErr = true;
                  errs.push('开始节点不能为连线终点');
                }
              } else if (item.type === 'End') {
                if (item.id === edges[i].source && !endEdgeErr) {
                  endEdgeErr = true;
                  errs.push('结束节点不能为连线起点');
                }
              }
            }
            if (!hasEdge && !edgeErr) {
              edgeErr = true;
              errs.push('节点间必需有连接线关联');
            }
          });
        }
        return {
          graphToJson,
          nodeList,
          edgeList,
          errs
        };
      },
      //保存流程图
      saveFlow() {
        // 先取消所有选中的节点和边, 防止把选中状态一起保存了
        this.graph.cleanSelection();
        const { errs, nodeList, edgeList, graphToJson } = this.checkFlow();
        console.log('nodeList', nodeList)
        console.log('edgeList', edgeList)
        console.log('saveData', {
          nodes: nodeList,
          edges: edgeList
        })
      },
      //历史状态改变
      historyChange() {
        this.canUndo = this.graph.history.canUndo();
        this.canRedo = this.graph.history.canRedo();
      },
      //撤销
      onUndo() {
        if (this.disabled) {
          return;
        }
        this.graph.history.undo();
      },
      //重做
      onRedo() {
        if (this.disabled) {
          return;
        }
        this.graph.history.redo();
      },
      getJson() {
        console.log(this.graph.toJSON());
      }
    }
  }
  </script>
  <style lang="scss" scoped>
  .graph-drawer-box{
    display: flex;
  }
  </style>