import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Checkbox from '../../checkbox/lib/Checkbox';
import StatusBox from '../../statusbox/lib/Statusbox';
// @require '../style/table.scss'

/**
 * 表格组件，封装以下功能：
 * 数据展示
 * 选中
 */
class Table extends React.Component {

  static propTypes = {
    style: PropTypes.object,
    className: PropTypes.string,
    /**
     * 配置每列表头
     */
    cols: PropTypes.arrayOf(PropTypes.shape({
      /**
       * 表格头部一列名称
       */
      display: PropTypes.any.isRequired,
      /**
       * 表格一列所占宽度百分比
       */
      width: PropTypes.number,
      /**
       * 跨列
       * 默认为1
       */
      colspan: PropTypes.number,
      /**
       * 为这个表头设置style,优先级高于width属性可以覆盖width属性
       */
      style: PropTypes.object,
    })),
    /**
     * 表格体的数据
     * 二维数组 如果数组元素是
     * React组件实例：展示元素本身
     * else：展示元素toString()
     * 如果数组元素是空字符串或者==null会显示为'-'
     * 会读取一维数组（data[i].style）的style属性作为<tr>的style
     * 会读取一维数组（data[i].className）的style属性作为<tr>的className
     */
    data: PropTypes.arrayOf(PropTypes.array).isRequired,
    /**
     * 是否可以选择行，可以的话会在左边显示checkbox来供选择
     */
    canSelect: PropTypes.bool,
    /**
     * 但被选中的行发生变化时回调
     * onSelectedChange(rowsSelectedChange)
     */
    onSelectedChange: PropTypes.func,
    /**
     * 当其中一行被onClick是回调 callback(data[i])
     */
    onRowClick: PropTypes.func,
    /**
     * 给相邻两行设置不同的背景颜色，做视觉区分
     */
    differentiateRow: PropTypes.bool,
    /**
     * 悬浮展示在表格的正中间
     */
    overlap: PropTypes.any,
    /**
     * 当没有数据时显示
     */
    noDataMsg: PropTypes.any,
  };

  static defaultProps = {
    canSelect: false,
    differentiateRow: true,
    noDataMsg: <StatusBox type="info" size="l">暂无数据</StatusBox>,
  };

  state = {
    /**
     * 全选是否选中
     */
    isSelectAll: false,
  };

  componentWillReceiveProps(nextProps) {
    const { data } = nextProps;
    this.shouldSelectAllChecked(data);
  }

  /**
   * 设置是否选中全部
   * @param checked 是否选中
   */
  applySelectAll = (checked) => {
    const { data } = this.props;
    data.forEach(one => {
      one.selected = checked;
    });
    this.setState({
      isSelectAll: checked,
    });
    this.notifySelectedChange(data);
  };

  /**
   * 选中或者不选中一个
   * @param checked
   * @param row
   */
  onSelectOne = (checked, row) => {
    row.selected = checked;
    this.forceUpdate();
    this.notifySelectedChange([row]);
  };

  /**
   * 选中或者不选中事件发生时通知
   * @param rows 发生变化的[row]
   */
  notifySelectedChange = (rows) => {
    const { data, onSelectedChange } = this.props;
    if (typeof onSelectedChange === 'function') {
      onSelectedChange(rows);
    }
    this.shouldSelectAllChecked(data);
  };

  /**
   * 检查当前选中全部checkbox是否需要选中
   */
  shouldSelectAllChecked = (data) => {
    // 如果data不是一个数组就不要显示isSelectAll
    if (!Array.isArray(data)) {
      this.setState({
        isSelectAll: false,
      });
      return;
    }
    // 检查data数组的每一个元素，只要有一个元素是没有selected就不要显示isSelectAll
    for (let i = 0; i < data.length; i++) {
      if (!data[i].selected) {
        this.setState({
          isSelectAll: false,
        });
        return;
      }
    }
    this.setState({
      isSelectAll: true,
    });
  };

  renderTHead() {
    let { cols, canSelect } = this.props;
    if (Array.isArray(cols)) {
      let { isSelectAll } = this.state;
      return (
        <tr>
          {canSelect ?
            <th title="全选" style={{ minWidth: '20px' }}>
              <Checkbox
                checked={isSelectAll}
                onChange={checked => {
                  this.applySelectAll(checked);
                }}
              />
            </th> : null}
          {cols.map((col, index) =>
            <th
              key={index}
              style={Object.assign({ width: `${col.width}%` }, col.style)}
              colSpan={col.colspan}
            >{col.display}
            </th>)
          }
        </tr>
      );
    }
    return null;
  }

  renderTBody = () => {
    let { data, canSelect, onRowClick, differentiateRow, cols } = this.props;
    if (Array.isArray(data) && data.length > 0) {
      return (
        data.map((row, rowIndex) => {
          let colSpan = 1;
          if (row.length === 1 && Array.isArray(cols)) {
            // 如果只有一个数据，则填充整行
            colSpan = cols.length;
          }
          return (
            <tr
              key={rowIndex}
              style={Object.assign(
                { backgroundColor: differentiateRow && rowIndex % 2 === 0 ? '#fcfcfc' : null },
                row.style)}
              className={row.className}
              onClick={() => {
                if (typeof onRowClick === 'function') {
                  onRowClick(row);
                }
              }}
            >
              {canSelect ?
                <td colSpan={colSpan}>
                  <Checkbox
                    checked={row.selected || false}
                    onChange={checked => this.onSelectOne(checked, row)}
                  />
                </td> : null}
              {row.map((col, colIndex) => <td key={colIndex} colSpan={colSpan}>{col == null || col === '' ? '-' : col}</td>)}
            </tr>
          );
        })
      );
    }
    return <tr className="im-table-empty"></tr>;
  };

  renderOverlap() {
    const { data, overlap, noDataMsg } = this.props;
    // overlap 优先级更高
    if (overlap != null) {
      return <div className="im-table-overlap">{overlap}</div>;
    }
    if (!Array.isArray(data) || data.length === 0) {
      // 当data为空时会显示 没有数据
      return <div className="im-table-overlap">{noDataMsg}</div>;
    }
  }

  render() {
    const { style, className } = this.props;
    return (
      <div className="im-table-wrap">
        <table className={classnames('im-table', className)} style={style}>
          <thead>{this.renderTHead()}</thead>
          <tbody>{this.renderTBody()}</tbody>
        </table>
        {this.renderOverlap()}
      </div>
    );
  }
}

export default Table;
