<template>
  <li class="node-li" :class="{ 'level1-node': level1, 'grandchildren-active': isGrandChildActive && active, 'is-expanded': isExpanded, 'lazy': isLazy }">
    <div class="node-content" @click="handleNodeClick" :class="{ 'active': isActive }" :style="{color:(!node['visibleFlag'] || node['visibleFlag'] === 'Y') ? '' : (isExpanded ? '#adc' : '#ccc')}">
      <span class="node-text" :data-id="node[props.key]" :data-title="node[props.label]" :data-inner-code="node[props.traceback]" @mouseenter="spanMouseenter" @mouseleave="spanMouseleave">
        <i class="fa" v-if="!level1" :class="{ 'fa-angle-right': ((node['isLeaf'] && node[props.children] && node[props.children].length) || !node['isLeaf']), 'dot': ((!node['isLeaf'] && !(node[props.children] && node[props.children].length)) || node['isLeaf']) }"></i>
        <span>{{node[props.label]}}</span>
      </span>
      <i class="fa" @click.stop="expandToggle" v-if="(node['isLeaf'] && node[props.children] && node[props.children].length) || !node['isLeaf']"></i>
      <tree-slot :node="node"></tree-slot>
    </div>
    <ul class="children-list" v-if="((node['isLeaf'] && node[props.children] && node[props.children].length) || !node['isLeaf']) && node[props.children] && node[props.children].length">
      <catalog-tree-node :node="item" :props="props" :active="active" v-for="item in node[props.children]" :key="item[props.key]"
        @node-active="handleChildNodeActive" @node-expand="handleChildNodeExpand"></catalog-tree-node>
    </ul>
  </li>
</template>

<script>
import emitter from '@src/mixins/emitter.js'
import TreeSlot from './TreeSlot.js'
export default {
  name: 'CatalogTreeNode',
  componentName: 'CatalogTreeNode',
  mixins: [emitter],
  components: {
    TreeSlot
  },
  data() {
    return {
      isExpanded: false,
      isActive: false,
      isGrandChildActive: false,
      isLazy: false,
      tooltipEl: null,
      lastOverEl: null
    }
  },
  props: {
    node: {
      type: Object,
      required: true
    },
    props: {
      type: Object,
      default: function () {
        return {
          children: 'children',
          label: 'name',
          key: 'ID',
          traceback: 'innerCode' // 可用来回溯父节点的属性
        }
      }
    },
    level1: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    active: {
      type: Object
    }
  },
  watch: {
    active(val) {
      this.watchActive()
    }
  },
  computed: {
    owner() {
      let parent = this.$parent || this.$root
      let name = parent.$options.componentName

      while (parent && (!name || name !== 'CatalogTree')) {
        parent = parent.$parent
        if (parent) {
          name = parent.$options.componentName
        }
      }
      if (parent) {
        return parent
      } else {
        return {}
      }
    }
  },
  created() {
    if (this.active) {
      this.watchActive()
    }
  },

  methods: {
    matchActive(matchTraceback) {
      if (!this.active) {
        return false
      }
      for (let key in this.active) {
        if (this.props.traceback === key) {
          if (matchTraceback && this.node[key] !== this.active[key]) {
            return false
          } else if (!this.active[key].startsWith(this.node[key])) {
            return false
          }
        } else if (this.node[key] !== this.active[key]) {
          return false
        }
      }
      return true
    },
    watchActive(val, oldVal) {
      if (this.matchActive()) {
        this.isActive = true
        this.isExpanded = true
        this.$nextTick(_ => {
          this.changeLevel1NodeActive()
        })
        this.$emit('node-expand', this.node, this)
        this.lazyLoadChildren()
      } else {
        this.isActive = false
      }
    },
    changeLevel1NodeActive() {
      if (this.isActive) {
        let parent = this
        while (parent && parent.node && !parent.level1) {
          parent = parent.$parent
        }
        if (parent && parent.node && parent.level1) {
          parent.$parent.$children.forEach(node => {
            node.isGrandChildActive = false
          })
          parent.isGrandChildActive = true
        }
      }
    },
    handleChildNodeActive(val, nodeData, instance) {
      this.isGrandChildActive = val
      this.$emit('node-active', val, nodeData, instance)
    },
    handleChildNodeExpand(nodeData, instance) {
      this.isExpanded = true
      this.$emit('node-expand', nodeData, instance)
    },
    expandToggle() {
      if (this.isExpanded) {
        this.isExpanded = false
      } else {
        this.isExpanded = true
        this.lazyLoadChildren()
      }
    },
    async lazyLoadChildren() {
      if (!this.node['isLeaf'] && (!this.node[this.props.children] || this.node[this.props.children].length === 0)) {
        this.isLazy = true
        await this.owner.handleLazy(this.node)
        this.isLazy = false
      }
    },
    handleNodeClick() {
      this.lazyLoadChildren()
      this.dispatch('CatalogTree', 'node-click', this.node, this)
    },
    spanMouseenter(evt) {
      if (evt.target.className === 'node-text'){
        let node = evt.target
        if (node.scrollWidth > node.clientWidth) { // 获取label溢出边界的节点
          this.tooltipEl = document.getElementById('tooltipForTreeNode')
          if (!this.tooltipEl){
            this.tooltipEl = document.createElement('div')
            this.tooltipEl.id = 'tooltipForTreeNode'
            this.tooltipEl.className = 'el-tooltip__popper is-dark'
            this.tooltipEl.style.position = 'absolute'
            this.tooltipEl.style.zIndex = 2000
            this.tooltipEl.style.display = 'none'
            this.tooltipEl.innerHTML = '<span id="tooltipForTreeNodeInner"></span><div x-arrow="" class="popper__arrow" style="top: 11px;"></div>'
            this.tooltipEl.setAttribute('x-placement', 'right')
            document.body.appendChild(this.tooltipEl)
          }
          let rect = node.getBoundingClientRect()
          this.tooltipEl.style.display = 'block'
          document.getElementById('tooltipForTreeNodeInner').innerHTML = node.innerText
          this.tooltipEl.style.top = rect.top + window.scrollY + 'px'
          this.tooltipEl.style.left = rect.left + window.scrollX + node.clientWidth + 'px'
          this.lastOverEl = node
        }
      }
    },
    spanMouseleave(evt) {
      if (evt.target.className === 'node-text'){
        let node = evt.target
        let toEl = evt.toElement
        if (node === this.lastOverEl && toEl && toEl !== node && !node.contains(toEl)) { // 获取label溢出边界的节点
          if (this.tooltipEl) {
            this.tooltipEl.style.display = 'none'
          }
        }
      }
    }
  }
}
</script>

<style scoped>
  .node-text {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
  }
  .node-content {
    position: relative;
  }
</style>
