<!--
Program: Tree Item
Author: SDL
Description: Tree Item Common Component
-->
<template>
  <li
    role="treeitem"
    :class="classes"
    :draggable="draggable"
    @dragstart.stop="onItemDragStart($event, self, self.model)"
    @dragend.stop.prevent="onItemDragEnd($event, self, self.model)"
    @dragover.stop.prevent="isDragEnter = true"
    @dragenter.stop.prevent="isDragEnter = true"
    @dragleave.stop.prevent="isDragEnter = false"
    @drop.stop.prevent="handleItemDrop($event, self, self.model)"
  >
    <div role="presentation" :class="wholeRowClasses" v-if="isWholeRow">&nbsp;</div>
    <i class="tree-icon tree-ocl" role="presentation" @click="handleItemToggle"></i>
    <div :class="anchorClasses" v-on="events">
      <i class="tree-icon tree-checkbox" role="presentation" v-if="showCheckbox && !model.loading"></i>
      <slot :vm="this" :model="model">
        <i :class="themeIconClasses" role="presentation" v-if="!model.loading"></i>
        <span v-text="model[textFieldName]"></span>
      </slot>
    </div>
    <div
      name="middleArea"
      style="width:100%;height:5px;position:absolute;z-index:1;"
      :class="{ 'tree-after-middle-area': isAfterMiddleArea }"
      @dragend.stop.prevent="onItemDragEnd($event, self, self.model)"
      @dragover.stop.prevent="isAfterMiddleArea = true"
      @dragenter.stop.prevent="isAfterMiddleArea = true"
      @dragleave.stop.prevent="isAfterMiddleArea = false"
      @drop.stop.prevent="handleItemDrop($event, self, self.model, parentItem, parent, 'after')"
    >
      <div class="arrow-top" v-show="isAfterMiddleArea" />
      <div class="arrow-bottom" v-show="isAfterMiddleArea" />
    </div>
    <ul role="group" ref="group" class="tree-children" v-if="isFolder" :style="groupStyle">
      <tree-item
        v-for="(child, index) in model[childrenFieldName]"
        ref="children"
        :before-item-click="beforeItemClick"
        :key="index"
        :data="child"
        :parent="self.model"
        :text-field-name="textFieldName"
        :value-field-name="valueFieldName"
        :children-field-name="childrenFieldName"
        :item-events="itemEvents"
        :whole-row="wholeRow"
        :show-checkbox="showCheckbox"
        :allow-transition="allowTransition"
        :height="height"
        :parent-item="model[childrenFieldName]"
        :draggable="draggable"
        :drag-over-background-color="dragOverBackgroundColor"
        :on-item-click="onItemClick"
        :on-item-toggle="onItemToggle"
        :on-item-drag-start="onItemDragStart"
        :on-item-drag-end="onItemDragEnd"
        :on-item-drop="onItemDrop"
        :klass="index === model[childrenFieldName].length - 1 ? 'tree-last' : ''"
      >
        <template v-slot="_">
          <slot :vm="_.vm" :model="_.model">
            <i :class="_.vm.themeIconClasses" role="presentation" v-if="!_.model.loading"></i>
            <span v-text="_.model[textFieldName]"></span>
          </slot>
        </template>
      </tree-item>
    </ul>
  </li>
</template>
<script>
export default {
  name: 'TreeItem',
  props: {
    data: { type: Object, required: true },
    textFieldName: { type: String },
    valueFieldName: { type: String },
    childrenFieldName: { type: String },
    itemEvents: { type: Object },
    wholeRow: { type: Boolean, default: false },
    showCheckbox: { type: Boolean, default: false },
    allowTransition: { type: Boolean, default: true },
    height: { type: Number, default: 24 },
    parentItem: { type: Array },
    parent: { type: Object },
    draggable: { type: Boolean, default: false },
    dragOverBackgroundColor: { type: String },
    beforeItemClick: {
      type: Function,
      default: () => true,
    },
    onItemClick: {
      type: Function,
      default: () => false,
    },
    onItemToggle: {
      type: Function,
      default: () => false,
    },
    onItemDragStart: {
      type: Function,
      default: () => false,
    },
    onItemDragEnd: {
      type: Function,
      default: () => false,
    },
    onItemDrop: {
      type: Function,
      default: () => false,
    },
    klass: String,
  },
  data() {
    return {
      isHover: false,
      isDragEnter: false,
      model: this.data,
      maxHeight: 0,
      events: {},
      isBeforeMiddleArea: false,
      isAfterMiddleArea: false,
      self: null,
    };
  },
  watch: {
    isDragEnter(newValue) {
      if (newValue) {
        this.$el.style.backgroundColor = this.dragOverBackgroundColor;
      } else {
        this.$el.style.backgroundColor = 'inherit';
      }
    },
    data(newValue) {
      this.model = newValue;
    },
    'model.opened': {
      // handler(val, oldVal) {
      handler() {
        this.onItemToggle(this, this.model);
        this.handleGroupMaxHeight();
      },
      deep: true,
    },
  },
  computed: {
    isFolder() {
      return (this.model[this.childrenFieldName] && this.model[this.childrenFieldName].length) || this.model.isFolder;
    },
    classes() {
      return [
        { 'tree-node': true },
        { 'tree-open': this.model.opened },
        { 'tree-closed': !this.model.opened },
        { 'tree-leaf': !this.isFolder },
        { 'tree-loading': !!this.model.loading },
        { 'tree-drag-enter': this.isDragEnter },
        { [this.klass]: !!this.klass },
      ];
    },
    anchorClasses() {
      return [
        { 'tree-anchor': true },
        { 'tree-disabled': this.model.disabled },
        { 'tree-selected': this.model.selected },
        { 'tree-hovered': this.isHover },
      ];
    },
    wholeRowClasses() {
      return [
        { 'tree-wholerow': true },
        { 'tree-wholerow-clicked': this.model.selected },
        { 'tree-wholerow-hovered': this.isHover },
      ];
    },
    themeIconClasses() {
      return [
        { 'tree-icon': true },
        { 'tree-themeicon': true },
        { [this.model.icon]: !!this.model.icon },
        { 'tree-themeicon-custom': !!this.model.icon },
        { 'tree-file': !this.isFolder },
      ];
    },
    isWholeRow() {
      if (this.wholeRow) {
        if (this.$parent.model === undefined) {
          return true;
        }
        return this.$parent.model.opened === true;
      }
      return false;
    },
    groupStyle() {
      return {
        position: this.model.opened ? '' : 'relative',
        'max-height': this.allowTransition ? `${this.maxHeight}px` : '',
        'transition-duration': this.allowTransition
          ? `${Math.ceil(this.model[this.childrenFieldName].length / 100) * 300}ms`
          : '',
        'transition-property': this.allowTransition ? 'max-height' : '',
        // display: this.allowTransition ? 'block' : this.model.opened ? 'block' : 'none',
        display: this.model.opened ? 'block' : 'none',
      };
    },
  },
  methods: {
    handleItemToggle() {
      if (this.isFolder) {
        this.model.opened = !this.model.opened;
        this.onItemToggle(this, this.model);
      }
    },
    handleGroupMaxHeight() {
      if (this.allowTransition) {
        let length = 0;
        let childHeight = 0;
        if (this.model.opened && this.$refs.children) {
          // eslint-disable-next-line prefer-destructuring
          length = this.$refs.children.length;
          this.$refs.children.forEach((child) => {
            childHeight += child.maxHeight;
          });
        }
        this.maxHeight = length * this.height + childHeight;
        // eslint-disable-next-line no-underscore-dangle
        if (this.$parent.$options._componentTag === 'tree-item' || this.$parent.$options.name === 'TreeItem') {
          this.$parent.handleGroupMaxHeight();
        }
      }
    },
    handleItemClick(e) {
      if (this.model.disabled) return;
      if (!this.beforeItemClick(this.model)) return;

      this.model.selected = !this.model.selected;
      this.onItemClick(this, this.model, e);
    },
    handleItemMouseOver() {
      this.isHover = true;
    },
    handleItemMouseOut() {
      this.isHover = false;
    },
    handleItemDrop(e, oriNode, oriItem, parentItem, parent) {
      this.$el.style.backgroundColor = 'inherit';
      this.isBeforeMiddleArea = false;
      this.isAfterMiddleArea = false;
      this.onItemDrop(e, oriNode, oriItem, parentItem, parent);
    },
  },
  created() {
    this.self = this;
    const events = {
      click: this.handleItemClick,
      mouseover: this.handleItemMouseOver,
      mouseout: this.handleItemMouseOut,
    };
    // for (const itemEvent in this.itemEvents) {
    Object.keys(this.itemEvents).forEach(itemEvent => {
      const itemEventCallback = this.itemEvents[itemEvent];
      if (Object.prototype.hasOwnProperty.call(events, itemEvent)) {
        const eventCallback = events[itemEvent];
        events[itemEvent] = event => {
          eventCallback(this.self, this.self.model, event);
          itemEventCallback(this.self, this.self.model, event);
        };
      } else {
        events[itemEvent] = event => {
          itemEventCallback(this.self, this.self.model, event);
        };
      }
    });
    this.events = events;

    if (this.$parent.model !== undefined && this.model.opened === true) {
      this.$parent.model.opened = true;
    }
  },
  mounted() {
    this.handleGroupMaxHeight();
  },
};
</script>

<style scoped>
.tree-after-middle-area {
  border-top: 1px solid #868e96;
  position: relative;
}

.tree-after-middle-area > .arrow-top {
  position: absolute;
  top: -6px;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 5px 0 0 5px;
  border-color: transparent transparent transparent #868e96;
}
.tree-after-middle-area > .arrow-bottom {
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 5px 5px 0 0;
  border-color: #868e96 transparent transparent transparent;
}
</style>
