<template>
  <Tree v-bind="$props" :render="currentRender"></Tree>
</template>
<script>
import create from '../utils/create'
import { Tree } from 'view-design'

const TREE_NODE_CLASS = 'ivu-tree-children'
const TREE_NODE_HOVER_PREFIX = 'tree-hover-'
const APPEND_BEFORE = 'before'
const APPEND_INNER = 'inner'
const APPEND_AFTER = 'after'
let READY_TO_APPEND = null
let APPEND_TO = null
let APPEND_TARGET = null

export default create({
  name: 'tree',
  components: {
    Tree
  },
  props: {
    ...Tree.props,
    draggable: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentRender () {
      return this.render || this.renderContent
    }
  },
  methods: {
    buildChild (node, child) {
      if (child) {
        if (node.children) {
          if (node.children.length > 0) {
            node.children.push(child)
          }
        } else {
          this.$set(node, 'children', [child])
        }
      }
    },
    handlerDragstart (e, { data }) {
      const { target } = e
      target.style.cursor = 'move'
      target.style.opacity = '.5'
      READY_TO_APPEND = data
    },
    handlerDragOver (e, { data }) {
      const { offsetY, target } = e
      if (this.isChildren(READY_TO_APPEND, data)) {
        READY_TO_APPEND.style.cursor = 'not-allowed'
        return
      }
      if (READY_TO_APPEND === data) {
        APPEND_TARGET = null
        target.style.cursor = 'not-allowed'
        return
      }
      const offset = offsetY / target.offsetHeight
      if (offset <= 0.33) {
        APPEND_TO = APPEND_BEFORE
      } else if (offset > 0.33 && offset < 0.66) {
        APPEND_TO = APPEND_INNER
      } else if (offset >= 0.66) {
        APPEND_TO = APPEND_AFTER
      }
      this.setBorderOffsetElement(target)
      APPEND_TARGET = data
    },
    handlerDragend (e, { root, node, data }) {
      const { target } = e
      target.style.cursor = 'pointer'
      this.clearBorder()
      target.style.opacity = '1'
      if (!APPEND_TARGET || this.isChildren(data, APPEND_TARGET)) {
        return
      }

      // 从树上移除节点，就是拖动的节点
      const removeNode = () => {
        const parent = root.find(el => el.children && el.children.indexOf(data.nodeKey) > -1).node
        const index = parent.children.indexOf(data)
        parent.children.splice(index, 1)
      }
      removeNode()
      // 把移除的节点根据前后位置及父级关系添加回去
      const doAppend = (isBefore) => {
        const parent = root.find(el => el.children && el.children.indexOf(APPEND_TARGET.nodeKey) > -1).node
        const index = parent.children.indexOf(APPEND_TARGET) + (isBefore ? 0 : 1)
        parent.children.splice(index, 0, data)
        if (parent.children.length === 0) {
          delete parent.children
        }
      }

      switch (APPEND_TO) {
        case APPEND_BEFORE:
          doAppend(true)
          break
        case APPEND_AFTER:
          doAppend(false)
          break
        case APPEND_INNER:
          // 先展开
          this.$set(APPEND_TARGET, 'expand', true)
          // 加载内容
          this.buildChild(APPEND_TARGET, data)
          break
      }

      this.$emit('on-drag', data, APPEND_TARGET, APPEND_TO, e)
      READY_TO_APPEND = null
      APPEND_TO = null
      APPEND_TARGET = null
    },
    isChildren (node, child) {
      const { children } = node
      if (!children || !children.map) return false
      let flag = children.some(c => c.nodeKey === child.nodeKey)
      if (!flag) {
        children.map(node => {
          flag = this.isChildren(node, child)
        })
      }
      return flag
    },
    setBorderOffsetElement (target) {
      this.clearBorder()
      let ul = target
      while (ul.className !== TREE_NODE_CLASS) {
        ul = ul.parentElement
      }
      ul.className = `${TREE_NODE_CLASS} ${TREE_NODE_HOVER_PREFIX}${APPEND_TO}`
    },
    clearBorder () {
      let temp = document.querySelectorAll(`
        .${TREE_NODE_HOVER_PREFIX}${APPEND_BEFORE},
        .${TREE_NODE_HOVER_PREFIX}${APPEND_INNER},
        .${TREE_NODE_HOVER_PREFIX}${APPEND_AFTER}
      `)
      for (let i = 0; i < temp.length; i++) {
        temp[i].className = TREE_NODE_CLASS
      }
    },
    renderContent (h, treeData) {
      const { data } = treeData
      const { handlerDragstart, handlerDragOver, handlerDragend } = this
      if (this.draggable) {
        return (
          <span
            draggable="true"
            on-dragstart={(e) => handlerDragstart(e, treeData)}
            on-dragover={(e) => handlerDragOver(e, treeData)}
            on-dragend={(e) => handlerDragend(e, treeData)}
            class={{ 'ivu-tree-title': true, 'ivu-tree-title-selected': data.selected }}
          >
            {data.title}
          </span>
        )
      } else {
        return (
          <span>{data.title}</span>
        )
      }
    }
  }
})
</script>
<style lang="scss">
.ivu-tree ul{
  border: 1px solid transparent;
  li {
    list-style: none;
    margin: 4px 0;
    padding: 0;
    white-space: nowrap;
    outline: 0;
  }
}
.tree-hover-before{
  border-top-color: #2d8cf0!important;
}
.tree-hover-inner{
  background-color: #5cadff;
  opacity: .5;
  span{
    color: #fff;
  }
}
.tree-hover-after {
  border-bottom-color: #2d8cf0!important;
}
</style>
