<template>
    <div class="flex-row"
         style="height: 100%">
        <div id="leftPanel"
             class="flex-col road"
             v-if="showLeftBar">
            <div class="flex1 flex-col panel"
                 style="height:0">
                <b class="panel-header">
                    <a-icon type="deployment-unit"/>
                    显示实体类
                </b>
                <a-spin :spinning="loadingTree" style="max-height: 500px;" class="auto-overflow flex1">
                    <a-checkbox v-model="checkAllEntcls" @change="onCheckAllChange"> 全选 </a-checkbox>
                    <a-tree checkable
                            :defaultSelectedKeys="selectTreeNodeIdList"
                            v-model="checkedKeys"
                            @select="onSelect"
                            @check="onCheckEntCls"
                            :treeData="treeData"
                            :selectedKeys.sync="selectTreeNodeIdList"
                            :expandedKeys.sync="expandedKeys"
                            :autoExpandParent="autoExpandParent"
                            class="entity-class-tree ">
                    </a-tree>
                </a-spin>
            </div>
            <div class="flex1 flex-col panel" style="height:0">
                <b class="panel-header">
                    <a-icon type="deployment-unit"/>
                    选择显示关系类
                </b>
                <a-spin :spinning="loadingChecked" class="auto-overflow" style="padding: 0 10px; margin: 5px -10px;">
                    <a-checkbox-group id="mycheck"
                                      :options="allRelClsNameList"
                                      v-model="checkedRelClsNameList"
                                      @change="onChangeRelClsCheckBox">
                    </a-checkbox-group>
                </a-spin>
            </div>
        </div>
        <a-spin :spinning="loadingChecked" class="flex1 panel flex-col" style="height: 100%">
            <chart-comp ref="chart"
                        @="getInfoTooltip"
                        :isShowContextMenu="true"
                        @reloadChart="reloadChart"
                        :nodes="nodes"
                        :links="links"
                        :enable="true"
                        :isShowChart="true"></chart-comp>
        </a-spin>

        <entity-cls-details-tooltip class="chart_tooltip"
                                    :id="tooltip.entClsID"
                                    :key="tooltip.entClsID"
                                    v-if="tooltip.entClsID"
                                    style="position: absolute;z-index: 1;border-radius: 3px"
                                    :style="{'left': tooltip.x, 'top': tooltip.y}"></entity-cls-details-tooltip>
        <link-details-tooltip class="chart_tooltip"
                              :id="tooltip.relClsID"
                              :key="tooltip.relClsID"
                              :entCls="relClsName"
                              v-if="tooltip.relClsID"
                              style="position: absolute;z-index: 1;border-radius: 3px"
                              :style="{'left': tooltip.x, 'top': tooltip.y}"></link-details-tooltip>
    </div>

</template>

<script>
  import chartComp from '@/views/knowledge/common/chart'
  import entityClsDetailsTooltip from '@/views/knowledge/common/entClsDetails.vue'
  import linkDetailsTooltip from '@/views/knowledge/common/linkDetails.vue'

  import { getAllEntityClass } from '@/api/graph/entityClass'
  import { getAllRelationClass } from '@/api/graph/relationClass'
  import { getGraphEntClsTree } from '@/api/graph/statisticalMap'
  

  // 获取路径参数
  function getQueryVariable(variable) {
    let url = window.location.hash
    let index = url.indexOf('?')
    var query = url.substring(index + 1, url.length)
    var vars = query.split('&')
    for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=')
      if (pair[0] == variable) {
        return pair[1]
      }
    }
    return ''
  }
  const gData = [] // 左侧实体类树

  const dataList = []
  // 根据树生成一个列表
  const generateList = (data) => {
    for (let i = 0; i < data.length; i++) {
      const node = data[i]
      const key = node.key
      dataList.push({key, title: node.entClsName, entClsName: node.entClsName})
      if (node.children) {
        generateList(node.children, node.key)
      }
    }
  }
  //  得到需要展开的父节点key
  const getParentKey = (key, tree) => {
    let parentKey
    for (let i = 0; i < tree.length; i++) {
      const node = tree[i]
      if (node.children) {
        if (node.children.some(item => item.key === key)) {
          parentKey = node.key
        } else {
          const tp = getParentKey(key, node.children)
          if (tp) {
            parentKey = tp
          }
        }
      }
    }
    return parentKey
  }
  // 遍历一个树节点 找寻所有的子id
  const getIdsList = (root) => {
    let ids = []
    if (root.entClsID) ids.push(root.entClsID)
    if (root.children && root.children.length) {
      for (let i = 0; i < root.children.length; i++) {
        ids = ids.concat(getIdsList(root.children[i]))
      }
    }
    return ids
  }
  export default {
    components: {chartComp, entityClsDetailsTooltip, linkDetailsTooltip},
    data() {
      return {
        loadingTree: false,
        loadingChecked: false,
        checkAllEntcls: true,
        nodes: null,
        links: null,
        tooltip: {entClsID: false, relClsID: false},
        relClsName: '',
        expandedKeys: [], // 要展开的节点
        searchValue: '', // 搜索的实体类名字
        autoExpandParent: true,
        gData,
        selectTreeNodeIdList: [],
        checkedKeys: [], // 默认全部选中
        relClsList: [], // 关系类列表
        allRelClsNameList: [],// 所有的关系类名列表
        checkedRelClsNameList: [], // 去重的关系类名列表
        allEntClassCache: [], // 初始页面缓存所有的实体类
        allLinksCache: [],  // 初始页面缓存所有的路径信息
        filEntClass: undefined, // 选择树处理后的实体类
        filLinks: undefined, // 处理后的路径信息links
        showLeftBar: true //是否显示左侧可选框
      }
    },
    computed: {
      /**
       * 默认初始全部选中的关系类
       **/
      checkedRelCls() {
        var checkedIdList = []
        this.relClsList.forEach((v, i) => {
          if (v.checked === undefined || v.checked === true) {
            checkedIdList.push(v.value)
          }
        })
        return checkedIdList
      },
      /**
       * 实际绑定在树上的变量,根据rootId可能有不同
       **/
      treeData() {
        var returnData = []
        if (this.rootId) {
          // 搜索根节点
          this.$utils.tree.walk(this.gData, (node) => {
            if (node.entClsID === this.rootId) {
              returnData = [node]
              return false
            }
          })
        } else {
          returnData = this.gData
        }
        // 如果有搜索字符串
        var searchStr = this.searchValue
        if (searchStr) {
          // 向上遍历到所有要展开的父节点
          const expandedKeys = dataList.map((item) => {
            if (item.title.indexOf(searchStr) > -1) {
              return getParentKey(item.key, returnData)  // 返回要展开的父节点keys
            }
            return null
          }).filter((item, i, self) => item && self.indexOf(item) === i)
          // 设定展开
          Object.assign(this, {
            expandedKeys,
            autoExpandParent: true
          })
          // 遍历整个树
          var showParentNodeList = []
          this.$utils.tree.walk(returnData, (node, index, way) => {
            if (node.entClsName.indexOf(searchStr) > -1) {
              node.style = ''
              showParentNodeList = showParentNodeList.concat(way)
            } else {
              node.style = 'display:none'
            }
          })
          for (var i = 0; i < showParentNodeList.length; i++) {
            showParentNodeList[i].style = ''
          }
        } else {
          // 没有搜索串,遍历清空display:none
          this.$utils.tree.walk(returnData, (node) => {
            node.style = ''
          })
        }
        return returnData
      }
    },
    created() {
      this.showLeftBar = getQueryVariable('showLeftBar') === 'false' ? false : true;
      let clsId = getQueryVariable('clsId')
      this.refreshEntityClassList(clsId)
      /**
       * 请求数据，获取所有实体类的信息，然后根据pid组装出实体类之间的关系
       * */
      this.loadingChecked = true
      Promise.all([getAllEntityClass(true), getAllRelationClass()]).then((resp) => {
        let links = []
        resp[0].data.forEach((v) => {
          v.id = v.entClsID
          v.label = v.entClsName
          if (v.pid !== null) {
            let fromId = v.pid, toId = v.entClsID
            const item = {
              id: fromId + '_' + toId
            }
            item.from = v.pid
            item.to = v.entClsID
            item.classType = 'dashed'
            links.push(item)
          }
        })
        var relClassNameTempMap = {}
        resp[1].data.forEach((v) => {
          const item = {
            label: v.relClsName,
            value: v.relClsID,
            checked: true
          }
          v.from = v.startID
          v.to = v.endID
          v.id = v.relClsID
          v.label = v.relClsName
          this.relClsList.push(item)
          relClassNameTempMap[v.relClsName] = true
        })
        //去掉重复关系类名
        for (let name in relClassNameTempMap) {
          this.allRelClsNameList.push({
            label: name,
            value: name
          })
          this.checkedRelClsNameList.push(name)
        }
        links = links.concat(resp[1])
        this.allEntClassCache = resp[0]
        this.filLinks = this.allLinksCache = links

        if (clsId) { // 路径中存在实体类id
          this.onCheckEntCls(this.checkedKeys)
        } else {
          this.drawChart(resp[0].data, links)
        }
        this.loadingChecked = false
      })
    },
    methods: {
      reloadChart(nodes, links) {
        this.drawChart(nodes, links)
      },
      /**
       * 画图
       * @params nodes: 处理好的实体数据, link: 处理好的关系数据
       * */
      drawChart(nodes, links) {
        this.nodes = nodes
        this.links = links
        this.$refs.chart.destroyChart() // 先清空chart实例，再绘图
        this.$refs.chart.reDraw(undefined, nodes, links)
      },
      /**
       * 获取实体或关系的悬浮框
       * @params event:zoomchart返回的event，args：zoomchart返回的变量，包含了当前点击的实体或关系的数据
       * */
      getInfoTooltip(event, args) {
        const vm = this
        this.$set(this.tooltip, 'x', event.pageX + 'px')
        this.$set(this.tooltip, 'y', event.pageY + 'px')
        if (args.clickNode) {
          vm.tooltip.entClsID = args.clickNode.data.entClsID
          vm.tooltip.relClsID = false
        } else if (args.clickLink) {
          vm.tooltip.entClsID = false
          vm.tooltip.relClsID = args.clickLink.data.relClsID
          vm.relClsName = args.clickLink.data.relClsName
        } else {
          vm.tooltip.entClsID = false
          vm.tooltip.relClsID = false
        }
      },
      // 全选
      onCheckAllChange() {
        const allEntCls = []
        this.allEntClassCache.map(v => {
          allEntCls.push(v.entClsID)
        })
        this.onCheckEntCls(this.checkAllEntcls ? allEntCls : [])
        this.checkedKeys = this.checkAllEntcls ? allEntCls : []
      },
      onSelect(keys, node) {
        let entClsID = node.node.dataRef.entClsID
        this.expandedKeys = keys // 选中展开的key
      },
      /**
       * 改变实体类
       */
      onCheckEntCls(checkedKeys) {
        // 过滤缓存中的实体类 得到新的实体类
        let entClass = this.allEntClassCache.filter((v, i) => {
          return checkedKeys.includes(v.entClsID)
        })
        // 过滤缓存中的实体类 保存到data中，用于过滤
        this.filEntClass = entClass
        // 过滤缓存中的路径信息 得到新的路径
        let links = this.allLinksCache.filter((v, i) => {
          if (v.classType === 'dashed') {
            return checkedKeys.includes(v.from) && checkedKeys.includes(v.to)
          } else if (v.relClsID) {
            return checkedKeys.includes(v.from) && checkedKeys.includes(v.to)
          }
        })
        const relClassNameTempMap = {},
          allRelClsNameList = [],
          checkedRelClsNameList = []
        // 重新计算关系类列表 去掉重名计算
        links.forEach((v) => {
          if (v.relClsName) {
            relClassNameTempMap[v.relClsName] = true;
          }
        })
        for (let name in relClassNameTempMap) {
          allRelClsNameList.push({
            label: name,
            value: name
          })
          checkedRelClsNameList.push(name)
        }
        this.allRelClsNameList = allRelClsNameList
        this.checkedRelClsNameList = checkedRelClsNameList
        // 改变关系类checkbox
        // 缓存到data中，方便计算路径信息
        this.filLinks = links
		//  过滤掉，节点不存在的边
        const chatLinks = links.filter((link) => {
          return checkedKeys.includes(link.from) && checkedKeys.includes(link.to)
        })
        // 重画chart
        this.drawChart(JSON.parse(JSON.stringify(entClass)), chatLinks)
      },
      /**
       * 进入页面刷新实体类树
       */
      refreshEntityClassList(clsId) {
        this.loadingTree = true
        getGraphEntClsTree().then((data) => {
          for (let i = 0; i < data.length; i++) {
            data[i]['key'] = data[i]['entClsID']
            data[i]['title'] = data[i]['entClsName']
            data[i]['scopedSlots'] = {title: 'custom'}
            if (!data[i]['pid']) {
              this.checkedKeys.push(data[i]['entClsID'])
            }
          }
          // 此处传固定的option
          const option = {
            idName: 'entClsID',
            pidName: 'pid',
            childName: 'children',
            returnList: []
          }
          let treeData = this.$utils.tree.listToTree(data, option) // 数组转成树
          if (clsId) {  // 如果路径中存在实体类id
            for (let z = 0; z < treeData.length; z++) {
              if (treeData[z]['entClsID'] === clsId) {
                this.checkedKeys = getIdsList(treeData[z])
              }
            }
          }
          this.gData = treeData
          generateList(treeData)  // 生成个列表
          const vm = this
          // 遍历树找到父节点下面的所有子节点
          this.$utils.tree.walk(treeData, function (node, index, way) {
            var id = clsId  // 路由中的id
            var myWay = []  // 需要找到的展开节点key
            if (node.key === id) {
              for (let i = 0; i < way.length; i++) {
                myWay.push(way[i]['key'])
              }
              vm.expandedKeys = myWay
              return false
            }
          })
          this.loadingTree = false
        })
      },
      /**
       *改变关系类checkbox
       */
      onChangeRelClsCheckBox(checkedValues) {
        let entClass, links
        if (this.filEntClass !== undefined) {
          entClass = this.filEntClass
        } else {
          entClass = this.allEntClassCache
        }
        links = this.filLinks.filter((v, i) => {
          if (v.classType === 'dashed') {
            return true
          } else if (v.relClsID) {
            return checkedValues.includes(v.relClsName)
          }
        })
        //  过滤掉，节点不存在的边
        const chartLinks = links.filter((link) => {
          return !!entClass.find(ent => (ent.id === link.from || ent.id === link.to))
        })
        // 重绘echart
        this.drawChart(entClass, chartLinks)
      }
    },
    watch: {},
    mounted() {

    }
  }
</script>

<style>
    /*覆盖样式加的id*/
    #mycheck.ant-checkbox-group {
        max-width: none;
    }

    .ant-spin-container {
        height: 100%;
    }
</style>
