<script>
import ObjectUtil from '../util/object';

let columnIdSeed = 1;

const defaults = {
  default: {
    order: ''
  },
  selection: {
    width: 48,
    minWidth: 48,
    realWidth: 48,
    order: '',
    className: 'qf-table-selection'
  },
  expand: {
    width: 48,
    minWidth: 48,
    realWidth: 48,
    order: ''
  },
  index: {
    width: 48,
    minWidth: 48,
    realWidth: 48,
    order: ''
  }
};

const forced = {
  selection: {
    renderHeader(h, { store }) {
      return <qf-checkbox
        disabled={store.data && store.data.length === 0}
        indeterminate={store.selection.length > 0 && !this.isAllSelected}
        nativeOn-click={this.toggleAllSelection}
        value={this.isAllSelected}/>;
    },
    renderCell(h, { row, column, store, $index }) {
      return <qf-checkbox
        nativeOn-click={(event) => event.stopPropagation()}
        value={store.isSelected(row)}
        disabled={column.selectable ? !column.selectable.call(null, row, $index) : false}
        on-input={() => {
          store.rowSelectedChanged(row);
        }}/>;
    },
    sortable: false,
    resizable: false
  },
  index: {
    renderHeader: function (h, { column }) {
      return column.label || '#';
    },
    renderCell: function (h, { rowIndex, column }) {
      let i = rowIndex + 1;
      const index = column.index;

      if (typeof index === 'number') {
        i = rowIndex + index;
      } else if (typeof index === 'function') {
        i = index(rowIndex);
      }
      return <div>{i}</div>;
    },
    sortable: false
  },
  expand: {
    renderHeader: function (h, { column }) {
      return column.label || '';
    },
    renderCell: function (h, { row, store }, proxy) {
      const expanded = store.expandRows.indexOf(row) > -1;
      return <div class={'table-expand-icon ' + (expanded ? 'table-expand-icon-expanded' : '')}
        on-click={e => proxy.handleExpandClick(row, e)}>
        <i class='iconfont qf-icon ic-ic_xiangxia'></i>
      </div>;
    },
    sortable: false,
    resizable: false,
    className: 'qf-table-expand'
  }
};

export default {
  name: 'QfTableColumn',
  props: {
    type: {
      type: String,
      default: 'default'
    },
    width: {},
    minWidth: {},
    single: Boolean,
    renderHeader: Function,
    prop: String,
    sortable: {
      type: [String, Boolean],
      default: false
    },
    resizable: {
      type: Boolean,
      default: true
    },
    fixed: [Boolean, String],
    reserveSelection: Boolean,
    label: String,
    columnKey: String,
    align: String,
    headerAlign: String,
    context: {},
    formatter: Function,
    validator: Function,
    index: [Number, Function] // 用于指定列位置
  },

  computed: {
    owner() {
      let parent = this.$parent;
      while (parent && !parent.tableId) {
        parent = parent.$parent;
      }
      return parent;
    },

    columnOrTableParent() {
      let parent = this.$parent;
      while (parent && !parent.tableId && !parent.columnId) {
        parent = parent.$parent;
      }
      return parent;
    }
  },

  created() {
    this.$options.render = h => h('div', this.$slots.default);

    let parent = this.columnOrTableParent;
    let owner = this.owner;
    this.columnId = (parent.tableId || parent.columnId) + '_column_' + columnIdSeed++;
    this.isSubColumn = owner !== parent;

    let type = this.type;
    const width = this.parseWidth(this.width);
    const minWidth = this.parseMinWidth(this.minWidth);

    let column = this.getDefaultColumn(type, {
      minWidth: minWidth,
      width: width,
      id: this.columnId,
      single: this.single,
      type: this.type,
      reserveSelection: this.reserveSelection,
      renderHeader: this.renderHeader,
      sortable: this.sortable === '' ? true : this.sortable,
      resizable: this.resizable,
      property: this.prop,
      fixed: this.fixed === '' ? true : this.fixed,
      label: this.label,
      className: this.className,
      context: this.context,
      formatter: this.formatter,
      align: this.align ? 'is-' + this.align : null,
      headerAlign: this.headerAlign ? 'is-' + this.headerAlign : (this.align ? 'is-' + this.align : null),
      renderCell: null,
      index: this.index
    });
    ObjectUtil.apply(column, forced[type] || {});
    if (column.type === 'selection' && column.single) {
      column.renderHeader = null;
    }

    this.columnConfig = column;
    let renderCell = column.renderCell;
    let _self = this;

    if (type === 'expand') {
      owner.renderExpanded = function (h, data) {
        return _self.$scopedSlots.default
          ? _self.$scopedSlots.default(data)
          : _self.$slots.default;
      };

      column.renderCell = function (h, data) {
        return <div class="cell">{renderCell(h, data, this._renderProxy)}</div>;
      };

      return;
    }

    column.renderCell = function (h, data) {
      if (_self.$scopedSlots.default) {
        renderCell = () => {
          let vnode = _self.$scopedSlots.default(data);
          if (vnode && vnode.length) {
            vnode.forEach(item => {
              item.data = item.data || {};
              item.data.refInFor = true;
            });
          }
          return vnode;
        };
      }

      if (!renderCell) {
        renderCell = _self.defaultRender;
      }

      return (<div class="cell">{renderCell(h, data)}</div>);
    };
  },

  destroyed() {
    if (!this.$parent) return;
    const parent = this.$parent;
    this.owner.store.removeColumn(this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
  },

  mounted() {
    const parent = this.columnOrTableParent;
    let columnIndex;
    if (!this.isSubColumn) {
      columnIndex = [].indexOf.call(parent.$refs.hiddenColumns.children, this.$el);
    } else {
      columnIndex = [].indexOf.call(parent.$el.children, this.$el);
    }
    this.owner.store.insertColumn(this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
  },

  methods: {
    defaultRender(h, { row, column, $index }) {
      const property = column.property;
      const value = property && ObjectUtil.getValueByPath(row, property);
      if (column && column.formatter) {
        return column.formatter(row, column, value, $index);
      }
      return value;
    },

    parseWidth(width) {
      if (width !== undefined) {
        width = parseInt(width, 10);
        if (isNaN(width)) {
          width = null;
        }
      }
      return width;
    },

    parseMinWidth(minWidth) {
      if (minWidth !== undefined) {
        minWidth = parseInt(minWidth, 10);
        if (isNaN(minWidth)) {
          minWidth = 80;
        }
      }
      return minWidth;
    },

    getDefaultColumn(type, options) {
      const column = {};

      ObjectUtil.apply(column, defaults[type || 'default']);

      for (let name in options) {
        if (options.hasOwnProperty(name)) {
          const value = options[name];
          if (typeof value !== 'undefined') {
            column[name] = value;
          }
        }
      }

      if (!column.minWidth) {
        column.minWidth = 80;
      }

      column.realWidth = column.width === undefined ? column.minWidth : column.width;

      return column;
    }
  },

  watch: {
    index(newVal) {
      if (newVal) {
        if (this.columnConfig) {
          this.columnConfig.index = newVal;
        }
      }
    },
    label(newVal) {
      if (this.columnConfig) {
        this.columnConfig.label = newVal;
      }
    },

    prop(newVal) {
      if (this.columnConfig) {
        this.columnConfig.property = newVal;
      }
    },

    align(newVal) {
      if (this.columnConfig) {
        this.columnConfig.align = newVal ? 'is-' + newVal : null;

        if (!this.headerAlign) {
          this.columnConfig.headerAlign = newVal ? 'is-' + newVal : null;
        }
      }
    },

    headerAlign(newVal) {
      if (this.columnConfig) {
        this.columnConfig.headerAlign = 'is-' + (newVal || this.align);
      }
    },

    width(newVal) {
      if (this.columnConfig) {
        this.columnConfig.width = this.parseWidth(newVal);
      }
    },

    minWidth(newVal) {
      if (this.columnConfig) {
        this.columnConfig.minWidth = this.parseMinWidth(newVal);
      }
    },

    fixed(newVal) {
      if (this.columnConfig) {
        this.columnConfig.fixed = newVal;
      }
    },

    sortable(newVal) {
      if (this.columnConfig) {
        this.columnConfig.sortable = newVal;
      }
    },

    formatter(newVal) {
      if (this.columnConfig) {
        this.columnConfig.formatter = newVal;
      }
    }
  }
};
</script>
