<template>
  <li
    @mouseenter="hoverItem"
    @click.stop="selectOptionClick"
    class="en-select-dropdown__item el-select-dropdown__item"
    v-show="visible"
    :class="{
      selected: itemSelected,
      'is-disabled': disabled || groupDisabled || limitReached,
      hover: hover
    }"
  >
    <span class="en-select-check" v-if="select.multiple"></span>
    <span
      @mouseenter="onNodeEnter"
      @mouseleave="onNodeLeave"
    >
      <slot :data="node.data" :node="node">
        <span :style="{ color: node.color }" :title="node.title">
          {{ currentLabel }}
        </span>
      </slot>
    </span>
    <div class="en-select-node__assist-wrapper" v-if="showAssist || node.assist">
      <div
        class="en-select-node__assist-wrapper-fixd"
        :style="{
              left: assistConfig.left + 'px',
              top: assistConfig.top + 'px'
            }"
        v-show="showNodeAssist"
      >
        <node-assist :node="node"></node-assist>
      </div>
    </div>
  </li>
</template>

<script type="text/babel">
import Emitter from "element-ui/src/mixins/emitter";
import { escapeRegexpString } from "element-ui/src/utils/util";
import { getValueIndex, selectValueEqual } from "./util";

// const isObj = (val) => Object.prototype.toString.call(val) === "[object Object]";

export default {
  mixins: [Emitter],

  name: "EnOption",

  componentName: "ElOption",

  inject: ["select"],

  components: {
    NodeAssist: {
      props: {
        node: {
          required: true
        }
      },
      render(h) {
        // const parent = this.$parent;
        const select = this.select ? this.select : this.$parent;
        const node = this.node;
        const { data } = node;
        return (
          select.$scopedSlots.assist
            ? select.$scopedSlots.assist({ node, data })
            : <span class='en-node-assist'>{ node.assist }</span>
        );
      }
    }
  },

  props: {
    value: {
      // required: true
    },
    node: Object,
    label: [String, Number],
    created: Boolean,
    disabled: {
      type: Boolean,
      default: false
    },
    showAssist: Boolean,
    filterNodeMethod: Function
  },

  data() {
    return {
      index: -1,
      groupDisabled: false,
      visible: true,
      hitState: false,
      hover: false,
      assistConfig: {
        left: 0,
        top: 0
      },
      showNodeAssist: false
    };
  },

  computed: {
    isObject() {
      return (
        Object.prototype.toString.call(this.value).toLowerCase() ===
        "[object object]"
      );
    },

    currentLabel() {
      return this.label || (this.isObject ? "" : this.value);
    },

    currentValue() {
      return this.value || this.label || "";
    },

    itemSelected() {
      if (!this.select.multiple) {
        return this.isEqual(this.currentValue, this.select.value);
      } else {
        return this.contains(this.select.value, this.value);
      }
    },

    limitReached() {
      if (this.select.multiple) {
        return (
          !this.itemSelected &&
          (this.select.value || []).length >= this.select.multipleLimit &&
          this.select.multipleLimit > 0
        );
      } else {
        return false;
      }
    }
  },

  watch: {
    currentLabel() {
      if (!this.created && !this.select.remote) {
        this.dispatch("ElSelect", "setSelected");
      }
    },
    value(val, oldVal) {
      const { remote, valueKey } = this.select;
      if (!this.created && !remote) {
        if (
          valueKey &&
          typeof val === "object" &&
          typeof oldVal === "object" &&
          val[valueKey] === oldVal[valueKey]
        ) {
          return;
        }
        this.dispatch("ElSelect", "setSelected");
      }
    }
  },

  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.showNodeAssist = true;
      }
    },

    onNodeLeave() {
      if (this.showAssist || this.node.assist) {
        this.showNodeAssist = false;
      }
    },
    isEqual(a, b) {
      const { dataMode, props } = this.select;
      let valueKey = this.select.valueKey;
      if (dataMode === "data") {
        valueKey = props.value;
      } else if (dataMode === "id-name") {
        valueKey = "id";
      }
      return selectValueEqual(a, b, valueKey);
    },

    contains(arr = [], value) {
      const { dataMode, props } = this.select;
      let valueKey = this.select.valueKey;
      if (dataMode === "data") {
        valueKey = props.value;
      } else if (dataMode === "id-name") {
        valueKey = "id";
      }

      return getValueIndex(arr, value, valueKey) > -1;
    },

    handleGroupDisabled(val) {
      this.groupDisabled = val;
    },

    hoverItem() {
      if (!this.disabled && !this.groupDisabled) {
        this.select.hoverIndex = this.select.options.indexOf(this);
      }
    },

    selectOptionClick() {
      if (this.disabled !== true && this.groupDisabled !== true) {
        this.dispatch("ElSelect", "handleOptionClick", [this, true]);
      }
    },

    queryChange(query) {
      console.log("queryChange", query);
      if (this.filterNodeMethod && typeof this.filterNodeMethod === "function" && this.node) {
        this.visible = this.filterNodeMethod(query, this.node.data, this.node);
      } else {
        this.visible =
          new RegExp(escapeRegexpString(query), "i").test(this.currentLabel) ||
          this.created;
      }
      if (!this.visible) {
        this.select.filteredOptionsCount--;
      }
    }
  },

  created() {
    this.select.options.push(this);
    this.select.cachedOptions.push(this);
    this.select.optionsCount++;
    this.select.filteredOptionsCount++;

    this.$on("queryChange", this.queryChange);
    this.$on("handleGroupDisabled", this.handleGroupDisabled);
  },

  beforeDestroy() {
    const { selected, multiple } = this.select;
    const selectedOptions = multiple ? selected : [selected];
    const index = this.select.cachedOptions.indexOf(this);
    const selectedIndex = selectedOptions.indexOf(this);

    // if option is not selected, remove it from cache
    if (index > -1 && selectedIndex < 0) {
      this.select.cachedOptions.splice(index, 1);
    }
    this.select.onOptionDestroy(this.select.options.indexOf(this));
  }
};
</script>
