<template>
  <el-popover
    placement="bottom-start"
    trigger="focus"
    v-model="visible"
    @show="$refs._Show_input.focus()"
    ref="_Root"
  >
    <el-tree
      ref="_Tree"
      :data="data"
      :key="treeKey"
      :node-key="treeKey"
      :props="treeProps"
      :accordion="!!accordion"
      :show-checkbox="!!showCheckbox"
      :check-strictly="includeNonLeaf == 2"
      @node-click="OnNodeClicked"
      @check-change="OnCheckChanged"
      :filter-node-method="filterNodeMethod"
      style="max-height: 240px; overflow: auto;"
    >
    </el-tree>
    <el-input slot="reference"
              ref="_Show_input"
              :placeholder="placeholder"
              v-model="label"
              :readonly="!filterNodeMethod"
              style="height: 100%; width: 100%; border-radius: 0;"
              :size="size || 'medium'"
              @blur="OnBlur"
              @focus="visible = true"
              @input="Filter"
              :clearable="!!clearable || !!filterNodeMethod"
    />
  </el-popover>
</template>

<script>
export default {
  name: "TreeSelect",
  props: [
    "data", "placeholder", "treeKey", "valueName", "labelName", "isLeaf", "childrenName", "filterNodeMethod", "disabledName",
    "accordion", "showCheckbox", "includeNonLeaf"/* 0: 全部节点, 1: 不包括非叶子, 2: 包括非叶子并且枝叶不关联*/, "formatter", "value",
    'size', 'clearable',
  ],
  data() {
    return {
      internalValue: null,
      internalValues: [],
      label: '',
      visible: false,
      treeProps: {
        label: this.labelName || 'label',
        value: this.valueName || 'value',
        children: this.childrenName || 'children',
        disabled: this.disabledName || 'disabled',
      },
    };
  },
  methods: {
    OnNodeClicked(data, node, ele) {
      this.$refs._Show_input.focus();
      if(this.showCheckbox)
        return;
      if(this.IsLeaf(data))
      {
        this.SetData(data);
        this.$emit('node-click', data);
        this.visible = false;
      }
    },
    IsLeaf(data) {
      return !!this.GetProp(data, this.isLeaf, false);
    },
    toggleMenu() {
      this.visible = !this.visible;
    },
    SetData(data) {
      if(this.showCheckbox)
      {
        let arr = [];
        let label = '';
        for(let i in data)
        {
          let d = data[i];
          label += this.GetProp(d, this.treeProps.label, '');
          if(i < data.length - 1)
            label += ',';
          arr.push(this.valueName ? this.GetProp(d, this.valueName, null) : d);
        }
        this.label = label;
        this.internalValues = arr;
        this.$emit('rawDataChanged', this.internalValues, data);
        this.$emit('input', this.FormatValue(this.internalValues));
      }
      else
      {
        this.label = this.GetProp(data, this.treeProps.label, '');
        this.internalValue = this.valueName ? this.GetProp(data, this.valueName, null) : data;
        this.$emit('rawDataChanged', this.internalValue, data);
        this.$emit('input', this.FormatValue(this.internalValue));
      }
    },
    GetProp(data, val, ret) {
      switch(typeof(val))
      {
        case 'function':
          return val(data);
        case 'string':
          return data[val];
        default:
          return ret;
      }
    },
    OnBlur($event) {
      if(this.$refs._Tree.$el.contains($event.relatedTarget)) // Tree事件
        return;
      this.visible = false;
      this.$emit('blur2');
    },
    Filter() {
      if(this.filterNodeMethod)
      {
        if(this.showCheckbox)
        {
          if(this.internalValues.length)
          {
            this.internalValues = [];
            this.$refs._Tree.setCheckedKeys([]);
            this.$emit('input', this.FormatValue(this.internalValues));
          }
        }
        else
        {
          if(this.internalValue)
          {
            this.internalValue = null;
            this.$refs._Tree.setCurrentKey(null);
            this.$emit('input', this.FormatValue(this.internalValue));
          }
        }
        this.$refs._Tree.filter(this.label);
      }
    },
    Clear() {
      if(this.showCheckbox)
      {
        this.internalValues = [];
        this.$refs._Tree.setCheckedKeys([]);
        this.$emit('input', this.FormatValue(this.internalValues));
      }
      else
      {
        this.internalValue = null;
        this.$refs._Tree.setCurrentKey(null);
        this.$emit('input', this.FormatValue(this.internalValue));
      }
    },
    OnCheckChanged(data) {
      this.$refs._Show_input.focus();
      if(!this.showCheckbox)
        return;
      let datas = this.$refs._Tree.getCheckedNodes();
      if(this.includeNonLeaf == 1)
      {
        datas = datas.filter((x) => this.IsLeaf(x));
      }
      this.SetData(datas);
      this.$emit('check-change', data, datas);
      //this.visible = false;
    },
    FormatValue(val) {
      if(typeof(this.formatter) === 'function')
        return this.formatter(val);
      else if(Array.isArray(this.formatter) && this.formatter.length > 0)
        return this.formatter[0](val);
      else if(typeof(this.formatter) === 'object' && this.formatter.hasOwnProperty('formatter'))
        return this.formatter['formatter'](val);
      else
        return val;
    },
    ParseValue(val) {
      if(typeof(this.formatter) === 'function')
        return this.formatter(val, true);
      else if(Array.isArray(this.formatter) && this.formatter.length > 1)
        return this.formatter[1](val);
      else if(typeof(this.formatter) === 'object' && this.formatter.hasOwnProperty('parser'))
        return this.formatter['parser'](val);
      else
        return val;
    },
    FindData(val) {
      let func = (node) => {
        if(!node || node.length === 0)
          return null;
        for(let v of node)
        {
          let vv = this.valueName ? this.GetProp(v, this.valueName, null) : v;
          if(vv == val)
            return v;
          let children = v[this.treeProps.children];
          if(children && children.length > 0)
          {
            vv = func(children);
            if(vv !== null)
              return vv;
          }
        }
        return null;
      }
      return func(this.data);
    },
    Sync() {
      if(this.showCheckbox)
      {
        let labels = [];
        let keys = [];
        for(let i in this.internalValues)
        {
          let data = this.FindData(this.internalValues[i]);
          if(data)
          {
            labels.push(this.GetProp(data, this.treeProps.label, ''));
            keys.push(data[this.treeKey]);
          }
        }
        this.label = labels.join(",");
        this.$refs._Tree.setCheckedKeys(keys);
      }
      else
      {
        let data = this.FindData(this.internalValue);
        if(data)
        {
          this.label = this.GetProp(data, this.treeProps.label, '');
          this.$refs._Tree.setCurrentKey(data[this.treeKey]);
        }
      }
    },
    Init() {
      if(this.value)
      {
        if(this.showCheckbox)
        {
          this.internalValues = this.ParseValue(this.value);
          this.Sync();
        }
        else
        {
          this.internalValue = this.ParseValue(this.value);
          this.Sync();
        }
      }
      else {
        this.label = '';
        this.Clear();
      }
    },
  },
  mounted() {
    this.Init();
  },
  watch: {
    visible: function (newVal, oldVal) {
      this.$emit('visible-change', newVal);
    },
    showCheckbox: function (newVal, oldVal) {
      this.Clear();
    },
    data: function (newVal, oldVal) {
      this.Sync();
    },
    value: function (newVal, oldVal) {
      //console.log(newVal, oldVal);
      this.Init();
    },
  }
}
</script>

<style scoped>
</style>
