<template>
  <div
    class="el-tree-node en-tree-node"
    :class="setLevelClass"
    @click.stop="handleClick"
    @contextmenu="$event => this.handleContextMenu($event)"
    v-show="node.visible"
    role="treeitem"
    tabindex="-1"
    :aria-expanded="expanded"
    :aria-disabled="node.disabled"
    :aria-checked="node.checked"
    :draggable="tree.draggable"
    @dragstart.stop="handleDragStart"
    @dragover.stop="handleDragOver"
    @dragend.stop="handleDragEnd"
    @drop.stop="handleDrop"
    ref="node"
    v-if="!node.hide"
  >
    <div
      class="el-tree-node__content"
      :style="{ 'padding-left': (node.level - 1) * tree.indent + 'px' }"
      :class="{
        hover: hover
      }"
    >
      <span
        @click.stop="handleExpandIconClick"
        :class="[
          { 'is-leaf': node.isLeaf, expanded: !node.isLeaf && expanded,'is-head-leaf':node.isLeaf&&!expanded&&node.level===1 },
          'el-tree-node__expand-icon'
        ]"
      >
        <!--          tree.iconClass ? tree.iconClass : 'el-icon-caret-right'-->
        <en-icon
          v-if="treeIcon"
          :name="treeIcon"
          size="10"
          :style="{
            color: node.data.iconColor ? node.data.iconColor : '#A9B5C6'
          }"
        ></en-icon>
        <div v-else style="width:10px"></div>
      </span>
      <span
        v-if="node.loading && !node.loaded"
        class="el-tree-node__loading-icon el-icon-loading"
      >
      </span>
      <el-checkbox
        v-if="showCheckbox && disabledShowCheck"
        v-model="node.checked"
        :indeterminate="node.indeterminate"
        :disabled="!!node.disabled"
        @click.native.stop
        @change="handleCheckChange"
      >
      </el-checkbox>
      <div class="en-tree-node__label-wrapper">
        <node-content
          :node="node"
          @mouseenter.native="onNodeEnter"
          @mouseleave.native="onNodeLeave"
        ></node-content>
        <div class="en-tree-node__assist-wrapper" v-if="showAssist || node.assist">
          &nbsp;
          <div
            class="en-tree-node__assist-wrapper-fixd"
            :style="{
              left: assistConfig.left + 'px',
              top: assistConfig.top + 'px'
            }"
            v-show="node.showAssist"
          >
            <node-assist :node="node"></node-assist>
          </div>
        </div>
      </div>
    </div>
    <el-collapse-transition>
      <div
        class="el-tree-node__children"
        v-if="!renderAfterExpand || childNodeRendered"
        v-show="expanded"
        role="group"
        :aria-expanded="expanded"
      >
        <en-tree-node
          :render-content="renderContent"
          :render-assist="renderAssist"
          :content-format="contentFormat"
          :assist-format="assistFormat"
          v-for="child in node.childNodes"
          :render-after-expand="renderAfterExpand"
          :show-checkbox="showCheckbox"
          :key="getNodeKey(child)"
          :node="child"
          @node-expand="handleChildNodeExpand"
          :expand-icon="expandIcon"
          :collpase-icon="collpaseIcon"
          :show-assist="showAssist"
        >
        </en-tree-node>
        <div
          v-if="!node.pageLoaded && node.pageSize && node.loaded"
          class="loading-area"
          :style="{ 'padding-left': node.level * tree.indent + 8 + 'px' }"
        >
          <div
            v-if="!node.loading"
            class="loading-more"
            @click.stop="lazyLoadMore"
          >
            加载更多 {{ node.remaining > 0 ? '(' + node.remaining + ')' : ''}}
          </div>
          <span
            v-else
            class="el-tree-node__loading-icon el-icon-loading"
          ></span>
        </div>
      </div>
    </el-collapse-transition>
  </div>
</template>

<script type="text/jsx">
// import ElCollapseTransition from "collapse-transition";
import ElCheckbox from "element-ui/packages/checkbox";
import emitter from "element-ui/src/mixins/emitter";
import { getNodeKey } from "./model/util";
// import { addResizeListener, removeResizeListener } from "element-ui/src/utils/resize-event";

export default {
  name: "EnTreeNode",

  componentName: "EnTreeNode",

  inject: {
    select: {
      default: null
    },
    transfer: {
      default: null
    }
  },

  mixins: [emitter],

  props: {
    node: {
      default() {
        return {};
      }
    },
    props: {},
    renderContent: Function,
    renderAssist: Function,
    contentFormat: Function,
    assistFormat: Function,
    renderAfterExpand: {
      type: Boolean,
      default: true
    },
    showCheckbox: {
      type: Boolean,
      default: false
    },
    expandIcon: {
      type: String,
      default: "jishuqi-jia"
    },
    collpaseIcon: {
      type: String,
      default: "jishuqi-jian"
    },
    showAssist: {
      type: Boolean,
      default: false
    }
  },

  components: {
    // ElCollapseTransition,
    ElCheckbox,
    NodeContent: {
      props: {
        node: {
          required: true
        }
      },
      render(h) {
        const parent = this.$parent;
        const tree = parent.tree;
        const node = this.node;
        const { data, store } = node;
        return (
          parent.renderContent
            ? parent.renderContent.call(parent._renderProxy, h, { _self: tree.$vnode.context, node, data, store })
            : tree.$scopedSlots.default
              ? tree.$scopedSlots.default({ node, data })
              : <span class='el-tree-node__label' title={ node.title } style={{ color: node.color }}>{ node.label || data.name }</span>
        );
      }
    },
    NodeAssist: {
      props: {
        node: {
          required: true
        }
      },
      render(h) {
        const parent = this.$parent;
        const tree = parent.tree;
        const node = this.node;
        const { data, store } = node;
        return (
          parent.renderAssist
            ? parent.renderAssist.call(parent._renderProxy, h, { _self: tree.$vnode.context, node, data, store })
            : tree.$scopedSlots.assist
              ? tree.$scopedSlots.assist({ node, data })
              : <span class='en-tree-node-assist'>{ node.assist }</span>
        );
      }
    }
  },

  data() {
    return {
      isTreeNode: true,
      tree: null,
      expanded: false,
      childNodeRendered: false,
      oldChecked: null,
      oldIndeterminate: null,
      assistMaxWidth: null,
      assistConfig: {
        left: 0,
        top: 0
      },
      hover: false
    };
  },

  computed: {
    treeIcon() {
      if (this.node.store.lazy && this.node.isLeaf) { // 懒加载，是叶子节点，不显示左侧图标
        return false;
      }
      if (this.node.store.lazy && !this.node.loaded) { // 懒加载
        return this.expanded ? this.collpaseIcon : this.expandIcon;
      }
      return this.node.childNodes.length > 0 ? (this.expanded ? this.collpaseIcon : this.expandIcon) : false
    },
    setLevelClass(p) {
      const classMap = {
        "is-expanded": this.expanded,
        "is-current": this.node.isCurrent,
        "is-hidden": !this.node.visible,
        "is-focusable": !this.node.disabled,
        "is-checked": !this.node.disabled && this.node.checked,
        "is-current-text": this.node.isCurrent && !this.showCheckbox,
        "is-stoped": this.node.data.enable === "001"
      }
      classMap[`tree-node-level-${this.node.level}`] = true
      return classMap
    },
    disabledShowCheck() {
      if (this.node.store.checkMode !== "parent-children" && this.node.disabled) {
        return false;
      }
      return true;
    },
    value() {
      return this.node.value
    },
    label() {
      return this.node.label
    },
    currentLabel() {
      return this.node.label
    }
  },
  watch: {
    "node.indeterminate"(val) {
      this.handleSelectChange(this.node.checked, val);
    },

    "node.checked"(val) {
      this.handleSelectChange(val, this.node.indeterminate);
    },

    "node.expanded"(val) {
      // eslint-disable-next-line no-return-assign
      this.$nextTick(() => this.expanded = val);
      if (val) {
        this.childNodeRendered = true;
      }
    }
  },

  methods: {
    onNodeEnter(e) {
      if (this.showAssist || this.node.assist) {
        const elRect = e.srcElement.getBoundingClientRect();
        this.assistConfig.left = elRect.right;
        this.assistConfig.top = elRect.top + (elRect.height / 2);
        this.node.showAssist = true;
      }
    },

    onNodeLeave() {
      if (this.showAssist || this.node.assist) {
        this.node.showAssist = false;
      }
    },

    lazyLoadMore() {
      this.node.loadData(null, null, true);
    },

    getNodeKey(node) {
      return getNodeKey(this.tree.nodeKey, node.data);
    },

    handleSelectChange(checked, indeterminate) {
      if (this.oldChecked !== checked && this.oldIndeterminate !== indeterminate) {
        this.tree.$emit("check-change", this.node.data, checked, indeterminate);
      }
      this.oldChecked = checked;
      this.indeterminate = indeterminate;
    },

    handleClick() {
      const store = this.tree.store;
      store.setCurrentNode(this.node);
      this.tree.$emit("current-change", store.currentNode ? store.currentNode.data : null, store.currentNode);
      this.tree.currentNode = this;
      if (this.tree.expandOnClickNode) {
        this.handleExpandIconClick();
      }
      if (this.tree.checkOnClickNode && !this.node.disabled) {
        this.handleCheckChange(null, {
          target: { checked: !this.node.checked }
        });
      }
      if (!this.tree.checkOnClickNode &&
        !this.node.disabled &&
        (this.node.isLeaf ||
          (!store.lazy && this.node.childNodes.length === 0) ||
          (store.lazy && this.node.childNodes.length === 0 && this.node.loaded)
        ) && this.showCheckbox
      ) {
        this.handleCheckChange(null, {
          target: { checked: !this.node.checked }
        });
      }
      this.tree.$emit("node-click", this.node.data, this.node, this);
    },

    handleContextMenu(event) {
      if (this.tree._events["node-contextmenu"] && this.tree._events["node-contextmenu"].length > 0) {
        event.stopPropagation();
        event.preventDefault();
      }
      this.tree.$emit("node-contextmenu", event, this.node.data, this.node, this);
    },

    handleExpandIconClick() {
      if (this.node.isLeaf) return;
      if (this.expanded) {
        this.tree.$emit("node-collapse", this.node.data, this.node, this);
        this.node.collapse();
      } else {
        this.node.expand();
        this.$emit("node-expand", this.node.data, this.node, this);
      }
    },

    handleCheckChange(value, ev) {
      const store = this.tree.store;
      const checkMode = store.checkMode;
      const lazy = store.lazy;
      if (checkMode === "siblings" && !lazy) { // 处理是否同个父节点
        const checkedNodes = store.getCheckedNodeData();
        const noParents = checkedNodes.filter((v) => {
          return v.parent !== this.node.parent
        });
        noParents.forEach((v) => {
          v.setChecked(false, false);
        })
      }
      if (store.checkLimit === 1) {
        const checkedNodes = store.getCheckedNodeData();
        const no = checkedNodes.filter((v) => {
          return v !== this.node
        });
        no.forEach((v) => {
          v.setChecked(false, false);
        })
      }
      this.node.setChecked(ev.target.checked, !this.tree.checkStrictly);
      this.$nextTick(() => {
        if (this.select) { // 如果是select下面
          this.dispatch("ElSelect", "handleTreeOptionSelect", [this, store.getCheckedNodeData()]);
        }
        this.tree.$emit("check", this.node.data, {
          checkedNodes: store.getCheckedNodes(),
          checkedKeys: store.getCheckedKeys(),
          halfCheckedNodes: store.getHalfCheckedNodes(),
          halfCheckedKeys: store.getHalfCheckedKeys()
        });
      });
    },

    handleChildNodeExpand(nodeData, node, instance) {
      this.broadcast("ElTreeNode", "tree-node-expand", node);
      this.tree.$emit("node-expand", nodeData, node, instance);
    },

    handleDragStart(event) {
      if (!this.tree.draggable) return;
      this.tree.$emit("tree-node-drag-start", event, this);
    },

    handleDragOver(event) {
      if (!this.tree.draggable) return;
      this.tree.$emit("tree-node-drag-over", event, this);
      event.preventDefault();
    },

    handleDrop(event) {
      event.preventDefault();
    },

    handleDragEnd(event) {
      if (!this.tree.draggable) return;
      this.tree.$emit("tree-node-drag-end", event, this);
    }

    // handleResize() {
    //   if (this.showAssist) {
    //     const assistEl = this.$el.querySelector(".en-tree-node__assist-wrapper");
    //     this.assistMaxWidth = assistEl.offsetWidth - 18;
    //     if (this.assistMaxWidth < 252) {
    //       assistEl.style.maxWidth = "252px";
    //     } else {
    //       assistEl.style.maxWidth = `${this.assistMaxWidth}px`;
    //     }
    //   }
    // }
  },

  created() {
    const parent = this.$parent;

    if (parent.isTree) {
      this.tree = parent;
    } else {
      this.tree = parent.tree;
    }

    const tree = this.tree;
    if (!tree) {
      console.warn("Can not find node's tree.");
    }

    const props = tree.props || {};
    const childrenKey = props["children"] || "children";

    this.$watch(`node.data.${childrenKey}`, () => {
      this.node.updateChildren();
    });

    if (this.node.expanded) {
      this.expanded = true;
      this.childNodeRendered = true;
    }

    if (this.tree.accordion) {
      this.$on("tree-node-expand", node => {
        if (this.node !== node) {
          this.node.collapse();
        }
      });
    }
    if (this.select) { // 如果select存在，则保存本身
      this.select.options.push(this);
      this.select.cachedOptions.push(this);
      this.select.optionsCount++;
      this.select.filteredOptionsCount++;
    }
    if (this.transfer) {
      this.transfer.options.push(this);
    }
  },

  mounted() {
    // addResizeListener(this.$el, this.handleResize);
  },

  beforeDestroy() {
    // if (this.$el && this.handleResize) removeResizeListener(this.$el, this.handleResize);
  }
};
</script>
<style lang="scss" scoped>
.en-tree-node {
  .el-tree-node__content {
    height: 36px;
    padding-right: 20px;
    &:hover {
      background-color: #f5f8fc;
    }
    &.hover {
      background-color: #f5f8fc;
    }
  }
  .en-tree-node__label-wrapper {
    flex: 1;
    display: flex;
    align-items: center;
    font-size: 12px;
    position: relative;
    display: flex;
    .en-tree-node__assist-wrapper {
      z-index: 9;
      flex: 1;
      position: relative;
      .en-tree-node__assist-wrapper-fixd {
        z-index: 3000;
        position: fixed;
        padding: 12px;
        background-color: #666975;
        font-size: 12px;
        color: #ffffff;
        top: 50%;
        transform: translate(17px, -50%);
        border-radius: 3px;
        &:after {
          content: " ";
          width: 0;
          height: 0;
          border-top: 5px solid transparent;
          border-right: 5px solid #666975;
          border-bottom: 5px solid transparent;
          position: absolute;
          left: -5px;
          top: 50%;
          transform: translateY(-50%);
        }
      }
    }
  }
  /deep/ {
    .el-checkbox {
      margin-right: 12px;
    }
    .el-tree-node__expand-icon.expanded {
      transform: rotate(0deg);
    }
    .el-tree-node__label {
      font-size: 12px;
    }
    .el-tree-node__content {
      .el-tree-node__expand-icon {
        padding: 6px;
        margin-left: 14px;
        line-height: 1;
        font-size: 12px;
        height: 12px;
        box-sizing: content-box;
        margin-right: 6px;
      }
      .is-head-leaf{
        padding: 0;
        margin-right: 0;
        margin-left: 8px;
      }
    }
  }
  .loading-area {
    font-size: 12px;
    color: #b9c4d2;
    height: 36px;
    line-height: 36px;
    .loading-more {
      color: #b9c4d2;
      cursor: pointer;
    }
  }
  &.is-stoped{
    color: #aeaeae;
  }
}
</style>
