<template>
  <ul role="tree-node" :class="className">
    <treeNode 
      v-for="item in treeData" 
      :key="item.eventKey"
      :node="item"
      :title="item.title"
      :pos="item.pos"
      :showIcon="item.showIcon"
      :loadData="item.loadData"
      :prefixCls="item.prefixCls"
      :expanded="item.expanded"
      :selected="item.selected"
      :eventKey="item.eventKey"
      :root="item.root"
      :disabled="item.disabled"
      :iconType="iconType"
      ></treeNode>
  </ul>
</template>

<script>
  import treeNode from './treeNode'
  import classNames from 'classnames'

  import {
    traverseTreeNodes,
    isInclude
  } from './util'

  export default {
    name: 'tree',
    components: {
      treeNode
    },
    props: {
      data: {
        type: Array,
        default () {
          return []
        }
      },
      config: {
        type: Object,
        default () {
          return {
            title: 'title',
            key: 'key'
          }
        }
      },
      prefixCls: {
        type: String,
        default: 'v-tree'
      },
      showLine: { // 是否展示连接线
        type: Boolean,
        default: false
      },
      showIcon: { // 是否展示 TreeNode title 前的图标，没有默认样式，如设置为 true，需要自行定义图标相关样式
        type: Boolean,
        default: false
      },
      selectable: {
        type: Boolean,
        default: true
      },
      multiple: { // 支持点选多个节点（节点本身）
        type: Boolean,
        default: false
      },
      checkable: { // 节点前添加 Checkbox 复选框
        type: Boolean,
        default: false
      },
      checkStrictly: { // checkable状态下节点选择完全受控（父子节点选中状态不再关联）
        type: Boolean,
        default: false
      },
      draggable: { // 设置节点可拖拽（IE>8）
        type: Boolean,
        default: false
      },
      autoExpandParent: { // 是否自动展开父节点
        type: Boolean,
        default: true
      },
      defaultExpandAll: { // 默认展开所有树节点
        type: Boolean,
        default: true
      },
      defaultExpandedKeys: { // 默认展开指定的树节点 string[]
        type: Array,
        default () {
          return []
        }
      },
      expandedKeys: { // 默认展开指定的树节点 string[] 以后所有节点无法展开和收拢
        type: Array,
        default () {
          return []
        }
      },
      selectedKeys: {
        type: Array,
        default () {
          return []
        }
      },
      defaultCheckedKeys: { // 默认选中复选框的树节点 string[]
        type: Array,
        default () {
          return []
        }
      },
      defaultSelectedKeys: { // 默认选中的树节点 string[]
        type: Array,
        default () {
          return []
        }
      },
      loadData: {
        type: Function
      },
      titleRender: {
        type: Function
      },
      iconType: {
        type: String,
        default: 'file'
      }
      // onExpand: {
      //   type: Function
      // },
      // onCheck: {
      //   type: Function
      // },
      // onSelect: {
      //   type: Function
      // },
      // onDragStart: {
      //   type: Function
      // },
      // onDragEnter: {
      //   type: Function
      // },
      // onDragOver: {
      //   type: Function
      // },
      // onDragLeave: {
      //   type: Function
      // },
      // onDrop: {
      //   type: Function
      // },
      // onDragEnd: {
      //   type: Function
      // },
      // onMouseEnter: {
      //   type: Function
      // },
      // onMouseLeave: {
      //   type: Function
      // },
      // onRightClick: {
      //   type: Function
      // }
    },
    data () {
      return {
        root: this,
        expandedKeys$: this.getDefaultExpandedKeys(),
        selectedKeys$: this.getDefaultSelectedKeys(),
        treeData: []
      }
    },
    computed: {
      className () {
        return classNames(this.prefixCls, {
          [`${this.prefixCls}-show-line`]: this.showLine
        })
      }
    },
    watch: {
      data (newVal) {
        this.treeData = this.loop(newVal)
      },
      expandedKeys$ (newVal) {
        this.treeData = this.loop(this.data)
      },
      selectedKeys$ (newVal) {
        this.treeData = this.loop(this.data)
      },
      expandedKeys (newVal) {
        this.expandedKeys$ = this.getDefaultExpandedKeys()
      },
      defaultExpandedKeys () {
        this.expandedKeys$ = this.getDefaultExpandedKeys()
      },
      selectedKeys (newVal) {
        this.selectedKeys$ = this.getDefaultSelectedKeys()
      },
      defaultSelectedKeys () {
        this.selectedKeys$ = this.getDefaultSelectedKeys()
      }
    },
    methods: {
      getFilterExpandedKeys (props, expandKeyProp, expandAll) {
        const keys = props[expandKeyProp]
        if (!expandAll && !props.autoExpandParent) {
          return keys || []
        }
        const expandedPositionArr = []
        if (props.autoExpandParent) {
          traverseTreeNodes(this.data, (item, index, pos, key) => {
            if (keys.indexOf(key) > -1) {
              expandedPositionArr.push(pos)
            }
          })
        }
        const filterExpandedKeysSet = {}
        traverseTreeNodes(this.data, (item, index, pos, key) => {
          if (expandAll) {
            filterExpandedKeysSet[key] = true
          } else if (props.autoExpandParent) {
            const isCurrentParentOfExpanded =
              expandedPositionArr.some(p => isInclude(pos.split('-'), p.split('-')))
            if (isCurrentParentOfExpanded) {
              filterExpandedKeysSet[key] = true
            }
          }
        })
        const filterExpandedKeys = Object.keys(filterExpandedKeysSet)
        return filterExpandedKeys.length ? filterExpandedKeys : keys
      },
      getDefaultExpandedKeys (willReceiveProps) {
        let props = this._props
        let expandedKeys = willReceiveProps
          ? undefined
          : this.getFilterExpandedKeys(
            props,
            'defaultExpandedKeys',
            props.defaultExpandedKeys.length ? false : props.defaultExpandAll
          )
        if ('expandedKeys' in props && props['expandedKeys'].length > 0) {
          expandedKeys = (
              props.autoExpandParent
                ? this.getFilterExpandedKeys(props, 'expandedKeys', false)
                : props.expandedKeys
            ) || []
        }
        return expandedKeys
      },
      getDefaultSelectedKeys (willReceiveProps) {
        let props = this._props
  
        const getKeys = (keys) => {
          if (this.multiple) {
            return [...keys]
          }
          if (keys.length) {
            return [keys[0]]
          }
          return keys
        }
        let selectedKeys = willReceiveProps ? undefined : getKeys(this.defaultSelectedKeys)
        if ('selectedKeys' in props && props['selectedKeys'].length > 0) {
          selectedKeys = getKeys(props.selectedKeys)
        }
        return selectedKeys
      },
      onExpand (treeNode) {
        const expanded = !treeNode.expanded
        const controlled = this['expandedKeys'].length > 0
        const expandedKeys = [...this.expandedKeys$]
        const index = expandedKeys.indexOf(treeNode.eventKey)
        if (expanded && index === -1) {
          expandedKeys.push(treeNode.eventKey)
        } else if (!expanded && index > -1) {
          expandedKeys.splice(index, 1)
        }
        if (!controlled) {
          this.expandedKeys$ = expandedKeys
        }
  
        this.$emit('onExpand', expandedKeys, { node: treeNode, expanded })

        // after data loaded, need set new expandedKeys
        if (expanded && this.loadData) {
          return this.loadData(treeNode).then(() => {
            if (!controlled) {
              this.expandedKeys$ = expandedKeys
            }
          })
        }
      },
      onSelect (treeNode) {
        const props = this._props
        const selectedKeys = [...this.selectedKeys$]
        const eventKey = treeNode.eventKey
        const index = selectedKeys.indexOf(eventKey)
        let selected
        if (index !== -1) {
          selected = false
          selectedKeys.splice(index, 1)
        } else {
          selected = true
          if (!props.multiple) {
            selectedKeys.length = 0
          }
          selectedKeys.push(eventKey)
        }
        const selectedNodes = []
        if (selectedKeys.length) {
          traverseTreeNodes(this.data, (item) => {
            if (selectedKeys.indexOf(item.key) !== -1) {
              selectedNodes.push(item)
            }
          })
        }
        const newSt = {
          event: 'select',
          node: treeNode,
          selected,
          selectedNodes
        }
        if (!(this.selectedKeys.length > 0)) {
          this.selectedKeys$ = selectedKeys
        }
        this.$emit('onSelect', selectedKeys, newSt)
      },
      onMouseEnter (e, treeNode) {
        this.$emit('onMouseEnter', { event: e, node: treeNode })
      },
      onMouseLeave (e, treeNode) {
        this.$emit('onMouseLeave', { event: e, node: treeNode })
      },
      onContextMenu (e, treeNode) {
        this.$emit('onRightClick', { event: e, node: treeNode })
      },
      loop (data, level = 0) {
        let ret = []
        data.forEach((item, index) => {
          let obj = {}
          const pos = `${level}-${index}`
          const key = item.key || pos
  
          obj = Object.assign({}, item, {
            key: key,
            eventKey: key,
            root: this.root,
            pos: key,
            loadData: this.loadData,
            prefixCls: this.prefixCls,
            showIcon: this.showIcon,
            expanded: this.expandedKeys$.indexOf(key) !== -1,
            selected: this.selectedKeys$.indexOf(key) !== -1,
            titleRender: this.titleRender
          })
  
          if (item.children) {
            obj.children = this.loop(item.children, pos)
          }
          ret.push(obj)
        })
        return ret
      }
    },
    created () {
      this.treeData = this.loop(this.data)
    }
  }

</script>

<style lang="less">
  @import url(../../assets/ant.less);

</style>
