<template>
  <div class="node-box" style="position: relative">
    <transition name="el-zoom-in-center">
      <div v-show="infoVisible" class="graph-info-box">
        <div class="graph-info-child">
          <div v-show="selectObj.type == 'edge'">
            <noumenon-edge-modify ref="noumenonEdgeModify"></noumenon-edge-modify>
          </div>
          <div v-show="selectObj.type == 'node'">
            <noumenon-modify ref="noumenonModify"></noumenon-modify>
          </div>
          <i class="el-icon-d-arrow-left" @click="infoVisible = false"></i>
        </div>
      </div>
    </transition>
    <transition name="el-zoom-in-center">
      <div v-show="treeInfoVisible" class="tree-graph-info">
        <div class="graph-info-child">
          <tree-graph-info ref="treeGraphInfo"></tree-graph-info>
          <i class="el-icon-d-arrow-right" @click="treeInfoVisible = false"></i>
        </div>
      </div>
    </transition>
    <!-- 为图谱准备一个具备大小（宽高）的Dom -->
    <div class="tree-container">
      <div class="graph-name-box">
        <label>本体名称： {{ graphName }}；</label>
        <label>节点数量：{{ nodeCount }}；</label>
        <label>关系属性数量：{{ edgeCount }}；</label>
        <label>值属性数量：{{ valueCount }}；</label>
      </div>
      <!--      <div class="tips-box">-->
      <!--        <label></label>-->
      <!--      </div>-->
      <div class="icon-box">
        <div class="icon icon-tree" @click="showTreeCom">
          <i title="树形图谱"></i>
        </div>
        <div class="icon icon-add" @click="showAddNodeDialog">
          <i title="新增概念"></i>
        </div>
        <div title="按住shift点选两节点可新增关系" :class="['icon icon-arrow', createEdgeModelFlag ? 'active' : '']" @click="changeCreateEdgeModel">
          <i title="按住shift点选两节点可新增关系"></i>
        </div>
        <div class="icon icon-remove" @click="removeNode">
          <i title="删除"></i>
        </div>
        <div class="icon icon-save" @click="backGraph">
          <i title="返回"></i>
        </div>
      </div>
      <div id="mountNode" style="width: 100%; height: 1000px"></div>
    </div>
    <el-dialog
        title="新增概念"
        :visible.sync="addNodeDialogVisible"
        width="40%">
      <el-form ref="addNodeForm" label-width="80px" :rules="addNodeRules" :model="addNodeCmd">
        <el-form-item label="概念名" prop="tagName">
          <el-input v-model="addNodeCmd.tagName"></el-input>
        </el-form-item>
        <el-form-item label="概念描述">
          <el-input v-model="addNodeCmd.label"></el-input>
        </el-form-item>
      </el-form>
      <el-button @click="addNodeDialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="submitAddNode">确 定</el-button>
    </el-dialog>
    <el-dialog
        title="新增关系"
        :visible.sync="addEdgeDialogVisible"
        @close="handleAddEdgeDialogClose"
        width="40%">
      <el-form ref="addEdgeForm" :model="addEdgeCmd" label-width="100px" :rules="addEdgeRules">
        <el-form-item label="关系名称" prop="edgeName">
          <el-input v-model="addEdgeCmd.edgeName"></el-input>
        </el-form-item>
        <el-form-item label="关系描述">
          <el-input v-model="addEdgeCmd.label"></el-input>
        </el-form-item>
        <el-form-item label="是否显示箭头">
          <el-radio v-model="addEdgeCmd.arrow" :label="true">是</el-radio>
          <el-radio v-model="addEdgeCmd.arrow" :label="false">否</el-radio>
        </el-form-item>
      </el-form>
      <el-button @click="addEdgeDialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="submitAddEdge">确 定</el-button>
    </el-dialog>
  </div>
</template>

<script>
import request from '@/utils/request';
import {config} from '@/components/graph/config';
import G6 from '@antv/g6';
import noumenonModify from '@/components/dialog/NoumenonModify';
import noumenonEdgeModify from '@/components/dialog/NoumenonEdgeModify';
import treeGraphInfo from '@/components/dialog/TreeGraphInfo';


G6.registerBehavior('click-add-edge', {
  // Set the events and the corresponding responsing function for this behavior
  getEvents() {
    return {
      'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
      mousemove: 'onMousemove', // The event is mousemove, the responsing function is onMousemove
      'edge:click': 'onEdgeClick',
    };
  },
  // The responsing function for node:click defined in getEvents
  onClick(ev) {
    const self = this;
    const node = ev.item;
    const graph = self.graph;
    // The position where the mouse clicks
    const point = {x: ev.x, y: ev.y};
    const model = node.getModel();
    if (self.addingEdge && self.edge) {
      graph.updateItem(self.edge, {
        target: model.id,
      });
      // 打开编辑新建关系的信息弹窗
      vm.showAddEdge(self.edge._cfg.model);
      self.edge = null;
      self.addingEdge = false;
    } else {
      // Add anew edge, the end node is the current node user clicks
      self.edge = graph.addItem('edge', {
        source: model.id,
        target: model.id,
      });
      self.addingEdge = true;
    }
  },
  // The responsing function for mousemove defined in getEvents
  onMousemove(ev) {
    const self = this;
    // The current position the mouse clicks
    const point = {x: ev.x, y: ev.y};
    if (self.addingEdge && self.edge) {
      // Update the end node to the current node the mouse clicks
      self.graph.updateItem(self.edge, {
        target: point,
      });
    }
  },
  // The responsing function for edge:click defined in getEvents
  onEdgeClick(ev) {
    const self = this;
    const currentEdge = ev.item;
    if (self.addingEdge && self.edge === currentEdge) {
      self.graph.removeItem(self.edge);
      self.edge = null;
      self.addingEdge = false;
    }
  },
});

var vm;
var graph;
var graphData;
var _ = require('lodash');
var nodeProps = {
  id: 'vid',
  label: 'properties.label',
  name: 'properties.tagName',
  labelName: 'properties.label'
};
var edgeProps = {
  source: 'srcId',
  target: 'dstId',
  name: 'properties.edgeName',
  label: 'properties.label',
  arrow: 'properties.arrow',
  labelName: 'properties.label'
}
// const subjectColors = ['#5F95FF', '#61DDAA', '#65789B', '#F6BD16', '#7262FD', '#78D3F8', '#9661BC', '#F6903D', '#008685', '#F08BB4'];
// const colorSets = G6.Util.getColorSetsBySubjectColors(subjectColors, '#fff', 'default', '#777');
export default {
  components: {
    'noumenon-modify': noumenonModify,
    'noumenon-edge-modify': noumenonEdgeModify,
    'tree-graph-info': treeGraphInfo
  },
  data() {
    return {
      qo: '',
      graphName: '',
      nodeCount: 0,
      edgeCount: 0,
      valueCount: 0,
      ontologyId: '',
      infoVisible: false, // 左侧信息栏显隐
      treeInfoVisible: false, // 右侧树形图谱
      clickNode: {id: '', name: ''},
      addNodeDialogVisible: false,
      addNodeCmd: {
        ontologyId: '',
        tagName: '',
        label: ''
      },
      arrowVisible: false, // 是否展示箭头方向
      createEdgeModelFlag: false, // 创建关系模式开关
      addEdgeDialogVisible: false,
      addEdgeCmd: {
        ontologyId: '',
        edgeName: '',
        label: '',
        source: '',
        target: '',
        arrow: false
      },
      selectObj: {
        type: '',
        value: {}
      },
      addNodeRules: {
        tagName: [
          {required: true, message: '请输入类名称', trigger: 'blur'},
        ],
      },
      addEdgeRules: {
        edgeName: [
          {required: true, message: '请输入类名称', trigger: 'blur'},
        ],
      },
    }
  },
  created() {
    vm = this;
    vm.ontologyId = this.$route.query.id;
    vm.qo = {
      pageNo: this.$route.query.pageNo,
      name: this.$route.query.name
    };
    vm.graphName = this.$route.query.graphName;
  },
  mounted() {
    vm.initGraph();
  },
  methods: {
    queryCount() {
      request({
        url: `/nebula_model/countallbyontologyid/${vm.ontologyId}`,
        method: 'get',
        data: {}
      }).then(res => {
        vm.nodeCount = res.data.gns;
        vm.edgeCount = res.data.gxs;
        vm.valueCount = res.data.zsxs;
      });
    },
    queryTagData() { // 查询图空间内节点关系
      vm.queryCount(); // 更新统计信息
      request({
        url: `/nebula_model/findrelationbyontologyid/${vm.ontologyId}`,
        method: 'post',
        data: {
          // ontologyId: vm.ontologyId
        }
      }).then(res => {
        res.data.nodes.forEach(node => {
          Reflect.ownKeys(nodeProps).forEach(key => {
            node[key] = _.get(node, nodeProps[key], '');
          });
        });
        res.data.relations.forEach(edge => {
          Reflect.ownKeys(edgeProps).forEach(key => {
            edge[key] = _.get(edge, edgeProps[key], '');
          });
          // 是否指向自己
          edge.type = edge.srcId === edge.dstId ? 'loop' : '';
          // 是否显示箭头
          edge.style = {endArrow: edge.arrow};
        });
        graphData = {
          nodes: res.data.nodes,
          edges: res.data.relations
        };
        // 读取数据
        graph.data(graphData);
        // 渲染图
        graph.render();
      });
    },
    initGraph: function () {
      this.destroyGraph();
      let mountNodeDom = document.getElementById("mountNode");
      let _width = mountNodeDom.clientWidth, _height = mountNodeDom.clientHeight;
      // 创建 G6 图实例
      if (graph == undefined || graph == null) {
        graph = new G6.Graph(config({width: _width, height: _height, id: 'mountNode'}));

        graph.on('aftercreateedge', (e) => {
          vm.showAddEdge(e.edge._cfg.model);
        });

        graph.on('canvas:click', (e) => {
          vm.selectObj = {
            type: '',
            value: {}
          };
          vm.clearStates();
          vm.infoVisible = false;
        });

        /*拖动节点-start*/
        // const forceLayout = graph.get('layoutController').layoutMethod;
        // graph.on('node:dragstart', function (e) {
        //   graph.layout();
        //   refreshDragedNodePosition(e);
        // });
        // graph.on('node:drag', function (e) {
        //   if (forceLayout) {
        //     forceLayout.execute();
        //   }
        //   refreshDragedNodePosition(e);
        // });
        // graph.on('node:dragend', function (e) {
        //   e.item.get('model').fx = null;
        //   e.item.get('model').fy = null;
        // });
        /*拖动节点-end*/

        graph.on('edge:click', function (e) { // 点击边事件
          let edge = e.item._cfg.model;
          if (!edge.name) {
            return;
          }
          let fields = [];
          if (edge.properties && edge.properties.nebulafieldsnapshot) {
            fields = edge.properties.nebulafieldsnapshot;
          }
          vm.showEdgeModifyCom({
            edgeName: edge.name,
            label: edge.labelName,
            arrow: edge.arrow,
            source: edge.srcId,
            target: edge.dstId
          }, fields);
          graph.getEdges().forEach((edge) => {
            graph.clearItemStates(edge);
          });
          graph.getNodes().forEach((node) => {
            graph.clearItemStates(node);
          });
          graph.setItemState(e.item, 'yourStateName', true);

        });

        graph.on('node:click', (e) => {
          if (!event.shiftKey && !vm.createEdgeModelFlag) { // 按住shift属于新增关系，不需要触发点击节点事件
            let node = e.item._cfg.model;
            vm.showNodeModifyCom({
              id: node.id,
              tagName: node.name,
              label: node.labelName
            }, _.get(node, 'properties.nebulafieldsnapshot', []));
            vm.clearStates();
            graph.setItemState(e.item, 'yourStateName', true);
          }

        });
      }
      vm.queryTagData();
    },
    destroyGraph() {
      try {
        if (graph != undefined && graph != null) {
          graph.clear();
          graph = null;
          document.getElementById("mountNode").innerHTML = "";
        }
      } catch (err) {
        console.log(err);
      }
    },
    clearStates() { // 清空选中状态
      graph.getNodes().forEach((node) => {
        graph.clearItemStates(node);
      });
      graph.getEdges().forEach((edge) => {
        graph.clearItemStates(edge);
      });
    },
    changeCreateEdgeModel() { // 切换模式，默认和添加关系模式之间切换
      vm.createEdgeModelFlag = !vm.createEdgeModelFlag;
      if (vm.createEdgeModelFlag) {
        graph.setMode("addEdge");
      } else {
        graph.setMode("default");
      }
    },
    showAddNodeDialog() {
      vm.addNodeCmd = {
        ontologyId: vm.ontologyId,
        tagName: '',
        label: ''
      };
      vm.addNodeDialogVisible = true;
    },
    submitAddNode() {
      request({
        url: `/nebula_model/insertmodelvertex`,
        method: 'post',
        data: {
          ontologyId: vm.ontologyId,
          tagName: vm.addNodeCmd.tagName,
          label: vm.addNodeCmd.label
        }
      }).then(res => {
        graph.addItem('node', {
          id: res.data.vid,
          name: vm.addNodeCmd.tagName,
          label: vm.addNodeCmd.tagName,
          labelName: vm.addNodeCmd.label
        });
        graphData.nodes = graph.save().nodes;
        graph.layout();
        vm.$message.success("新增类成功");
        vm.addNodeDialogVisible = false;

        vm.showNodeModifyCom(res.data.ob, []);
      });
    },
    showAddEdge(edge) {
      vm.addEdgeCmd = {
        ontologyId: vm.ontologyId,
        edgeName: '',
        label: '',
        arrow: false,
        source: edge.source,
        target: edge.target
      };
      vm.addEdgeDialogVisible = true;
    },
    handleAddEdgeDialogClose() {
      vm.queryTagData();
    },
    submitAddEdge() {
      vm.$refs['addEdgeForm'].validate((valid) => {
        if (!valid) {
          return;
        }
        let edge = {
          srcId: vm.addEdgeCmd.source,
          ontologyId: vm.ontologyId,
          dstId: vm.addEdgeCmd.target,
          edgeName: vm.addEdgeCmd.edgeName,
          arrow: vm.addEdgeCmd.arrow,
          label: vm.addEdgeCmd.label
        };
        request({
          url: `/nebula_model/insertmodeledge`,
          method: 'post',
          data: edge
        }).then(res => {
          vm.queryTagData();
          vm.$message.success("新增关系成功");
          vm.addEdgeDialogVisible = false;

          vm.showEdgeModifyCom(edge, []);
        });
      });
    },
    showTreeCom() { // 显示树形图谱窗口
      vm.treeInfoVisible = true;
      vm.$nextTick(() => {
        vm.$refs['treeGraphInfo'].queryTreeData(vm.ontologyId);
      });
    },
    showNodeModifyCom(node, fields) { // 显示节点编辑组件
      vm.infoVisible = true;
      vm.$nextTick(() => {
        vm.selectObj = {
          type: 'node',
          value: node
        };
        vm.$refs['noumenonModify'].updateValue(node.tagName, node.label, fields);
      });
    },
    showEdgeModifyCom(edge, fields) { // 显示关系编辑组件
      vm.infoVisible = true;
      vm.selectObj = {
        type: 'edge',
        value: edge
      };
      vm.$nextTick(() => {
        vm.$refs['noumenonEdgeModify'].updateValue(edge.edgeName, edge.label, edge.arrow, fields, vm.selectObj.value.source, vm.selectObj.value.target);
      });
    },
    backGraph() { // 返回
      if(vm.$refs['treeGraphInfo']) {
        vm.$refs['treeGraphInfo'].destroyTree();
      }
      vm.$router.push({path: "/graphModel", query: {pageNo: vm.qo.pageNo, name: vm.qo.name}})
      vm.$message.success("保存成功");
    },
    changeArrowVisible() { // 显隐箭头
      vm.arrowVisible = !vm.arrowVisible;
      vm.queryTagData();
    },
    removeNode() { // 删除节点
      if (vm.selectObj.type.length === 0) {
        vm.$message.warning("请先选中节点或关系");
        return;
      }
      this.$confirm('此操作将永久删除选中节点和关系, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        if (vm.selectObj.type === "node") {
          request({
            url: `/nebula_model/deletemodelvertex/${vm.selectObj.value.id}`,
            method: 'get',
            data: {
              // vid: vm.selectObj.value.id
            }
          }).then(res => {
            vm.$message.success("删除成功");
            vm.queryTagData();
            vm.infoVisible = false;
          });
        } else if (vm.selectObj.type === "edge") {
          request({
            url: `/nebula_model/deletemodeledge`,
            method: 'post',
            data: {
              srcId: vm.selectObj.value.source,
              dstId: vm.selectObj.value.target,
            }
          }).then(res => {
            vm.$message.success("删除成功");
            vm.queryTagData();
            vm.infoVisible = false;
          });
        }
      }).catch(() => {
      });
    },
    submitUpdateNode(modifyCmd) { // 更新
      request({
        url: `/nebula_model/insertmodelvertex`,
        method: 'post',
        data: {
          vid: vm.selectObj.value.id,
          tagName: modifyCmd.tagName,
          label: modifyCmd.label,
          fields: modifyCmd.fields
        }
      }).then(res => {
        vm.queryTagData();
        vm.$message.success("保存成功");
      });
    },
    submitUpdateEdge(modifyCmd) {
      request({
        url: `/nebula_model/insertmodeledge`,
        method: 'post',
        data: {
          edgeName: modifyCmd.edgeName,
          label: modifyCmd.label,
          fields: modifyCmd.fields,
          arrow: modifyCmd.arrow,
          srcId: vm.selectObj.value.source,
          dstId: vm.selectObj.value.target,
        }
      }).then(res => {
        vm.queryTagData();
        vm.$message.success("保存成功");
      });
    },
  }
}

function refreshDragedNodePosition(e) {
  const model = e.item.get('model');
  model.fx = e.x;
  model.fy = e.y;
}
</script>

<style scoped>
.graph-name-box {
  position: absolute;
  top: 25px;
  left: 65px;
  width: 700px;
  font-size: 18px;
  font-weight: bold;
}


.form-title {
  font-size: 16px;
  margin: 15px 0;

}

.add-attribute-box {
  margin-top: 10px;
  color: #409EFF;
  cursor: pointer;
  text-align: right;
}

.graph-info-box, .tree-graph-info {
  position: absolute;
  width: 500px;
  top: 0px;
  overflow: hidden;
  bottom: 0;
  background-color: #fff;
  padding: 15px;
  z-index: 999;
  border-right: 1px solid rgba(52, 100, 224, 0.15);
  box-shadow: 0px 2px 21px 0px rgba(52, 100, 224, 0.15);
}

.graph-info-box {
  left: 0px;
}

.tree-graph-info {
  right: 0;
}

.graph-info-child {
  width: 100%;
  height: 100%;
  position: relative;
}

.el-icon-d-arrow-left, .el-icon-d-arrow-right {
  position: absolute;
  top: 50%;
  margin-top: -10px;
  font-size: 20px;
  cursor: pointer;
  z-index: 1000;
}

.el-icon-d-arrow-left {
  right: 0px;
}

.el-icon-d-arrow-right {
  left: 0px;
}

.info-line-item {
  margin-bottom: 35px;
}

.info-title {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 12px;
}

.info-content > div {
  margin-bottom: 5px;
  line-height: 20px;
}

ol, ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.menu {
  /*这个样式不写，右键弹框会一直显示在画布的左下角*/
  position: absolute;
  background: white;
  border-radius: 5px;
  border: 1px solid #f2f4f7;
  left: -99999px;
  top: -999999px;
}

.menu div {
  list-style: none;
  padding: 5px 10px;
  color: black;
  border-bottom: 1px dashed #ffffff;
  font-size: 14px;
  cursor: pointer;
}

.menu div:hover {
  color: #659bc5;
  background: #f3f6fa;
}

.menu div:last-child {
  border-bottom: none;
}

ul#menuBox li {
  cursor: pointer;
  margin: 5px 0;
}

ul#menuBox li:hover {
  color: #1c63e0;
}

.tree-container {
  position: relative;
}

.tips-box {
  position: absolute;
  top: 25px;
  left: 50%;
  width: 300px;
  margin-left: -150px;
  font-size: 16px;
}

div.icon-box {
  position: absolute;
  top: 25px;
  right: 75px;
}

div.icon {
  display: inline-block;
  cursor: pointer;
  padding: 15px;
  background-color: #fff;
  border-radius: 40px;
  margin-left: 15px;
}

div.icon i {
  width: 25px;
  height: 25px;
  margin: auto;
  display: inline-block;
}


div.icon-add i {
  background: url("../../assets/image/icon/bg-add.png") no-repeat center/contain;
}


div.icon-remove i {
  background: url("../../assets/image/icon/changyonggoupiaorenshanchu.png") no-repeat center/contain;
}


div.icon-save i {
  background: url("../../assets/image/icon/fanhui.png") no-repeat center/contain;
}

div.icon-arrow i {
  background: url("../../assets/image/icon/arrowTop-fill.png") no-repeat center/contain;
}


div.icon-tree i {
  background: url("../../assets/image/icon/shuxingicon.png") no-repeat center/contain;
}

div.icon-arrow.active i {
  background: url("../../assets/image/icon/arrowTop-fill-active.png") no-repeat center/contain;
}

div.icon-arrow.active {
  box-shadow: 0px 0px 6px #979797;
}

.node-box {
  height: 100%;
}


</style>
