// @flow
import React from 'react';
import ReactDOM from 'react-dom';
import { Component, PropTypes } from '../../libs';
import { enhanceColumns, calculateFixedWidth, scheduleLayout } from './mixins';
import { getScrollBarWidth } from './utils';
import TableHeader from './TableHeader';
import TableBody from './TableBody';
import TableFooter from './TableFooter';
import i18n from '../locale';

import type {
  TableProps,
  TableState,
  DefaultTableProps
} from './Types';

let tableIdSeed = 1;

export default class Table extends Component{
  props: TableProps;
  state: TableState;
  static defaultProps: DefaultTableProps;

  constructor(props: Object, context: Object){
    super(props, context);
    this.tableId = tableIdSeed++;

    const { columns, data } = this.props;
    const enhCols = enhanceColumns(columns, this.tableId);

    this.state = {
      columns: columns,//用户原始columns配置
      _columns: enhCols.columns,//补充后的列配置
      fixedLeftColumns: enhCols.fixedLeftColumns,
      fixedRightColumns: enhCols.fixedRightColumns,
      data: data,
      sortList: null,
      filterList: null,

      bodyWidth: '',
      bodyHeight: '',
      headerHeight: '',
      realTableHeaderHeight: '',
      realTableHeight: '',
      realTableWidth: '',
      resizeProxyVisible: false,

      scrollY: false,//表格竖Y轴是否有滚动条,
      scrollX: false
    }
  }

  getChildContext(){
    return {
      $owerTable: this,
      stripe: this.props.stripe,
    }
  }

  componentDidMount(){
    this.initLayout();

    const des:Object = {
      get: this._filterContainer.bind(this)
    };
    Object.defineProperty(this, 'filterContainer', des);
  }

  componentWillUnmount(){
    if (this._filterContainer instanceof HTMLElement) {
      const body = document.body || document;
      ReactDOM.unmountComponentAtNode(this.filterContainer);
      body.removeChild(this.filterContainer);
    }
  }

  componentWillReceiveProps(nextProps: Object){
    if(nextProps.data != this.props.data){
      this.setState({data: nextProps.data}, ()=>{
        this.initLayout();
      });
    }

    if(nextProps.height != this.props.height){
      this.initLayout();
    }
  }

  _filterContainer(){
    if(!this._filterCon){
      this._filterCon = document.createElement('div');
      this._filterCon.style.cssText = "position:absolute;left:0;top:0";
      this._filterCon.id = "__filter__" + Math.random().toString().slice(2);
      const body = document.body || document.createElement('body');
      body.appendChild(this._filterCon);
    }

    return this._filterCon;
  }

  initLayout(){
    const { height, fit, maxHeight } = this.props;

    let rootComputedStyle = window.getComputedStyle(this.refs.root);
    let headerComputedStyle = window.getComputedStyle(this.refs.headerWrapper);
    let thisTableWidth = parseFloat(headerComputedStyle.getPropertyValue('width'));
    let realTableHeight = parseFloat(rootComputedStyle.getPropertyValue('height'));
    let bodyWidth = scheduleLayout(this.state._columns, thisTableWidth, 0, fit).bodyWidth;
    let headerHeight = this.refs.headerWrapper.offsetHeight;
    let  bodyHeight;

    if(height){
      bodyHeight = height - headerHeight;
    }else if(maxHeight && maxHeight < realTableHeight){//流体布局
      realTableHeight = maxHeight;
      bodyHeight = maxHeight - headerHeight;
    }else{
      bodyHeight = '';
    }

    this.setState({
      bodyWidth,
      bodyHeight,
      headerHeight,
      realTableHeaderHeight: headerHeight,
      realTableWidth: thisTableWidth,
      realTableHeight: this.props.height || realTableHeight || ''
    }, ()=>{
      this.adjustScrollState();
    });
  }

  scheduleLayout(){
    const { _columns, realTableWidth, scrollY } = this.state;

    const layout = scheduleLayout(_columns, realTableWidth, Number(scrollY), this.props.fit);
    this.setState({
      bodyWidth: layout.bodyWidth
    }, ()=>{
      this.onScrollBodyWrapper();
      this.adjustScrollState();
    });
  }

  adjustScrollState(){
    const scrollY = this.refs.mainBody.isScrollY();
    this.setState({
      scrollX: this.refs.mainBody.isScrollX(),
      scrollY: scrollY,
      bodyWidth: scheduleLayout(this.state._columns, this.state.realTableWidth, scrollY, this.props.fit).bodyWidth
    });
  }

  getBodyWrapperStyle(){
    const { bodyHeight } = this.state;
    const style = {};

    style.height = bodyHeight;
    return style;
  }

  onScrollBodyWrapper(){
    const target = arguments[0] ? arguments[0].target : this.refs.bodyWrapper;
    const headerWrapper = this.refs.headerWrapper;
    const fixedBodyWrapper = this.refs.fixedBodyWrapper;
    const rightFixedBodyWrapper = this.refs.rightFixedBodyWrapper;

    if(target instanceof HTMLDivElement){
      headerWrapper.scrollLeft = target.scrollLeft;
      fixedBodyWrapper && (fixedBodyWrapper.scrollTop = target.scrollTop);
      rightFixedBodyWrapper && (rightFixedBodyWrapper.scrollTop = target.scrollTop);
    }
  }

  sortBy(sort: number, prop: string, compare: any){
    const data = this.state.filterList || this.state.data;
    const sortList = data.slice(0);

    if(sort === 0){
      this.setState({sortList: null});
    }else{
      const defaultCompare = (a, b)=>{
        if(sort == 2){ var t = b; b = a; a = t;}
        return (a[prop] > b[prop] ? 1 : -1);
      }
      sortList.sort(compare ? compare : defaultCompare);
      this.setState({sortList});
    }
  }

  filterBy(column: Object, filteCondi: Array<Object>){
    const data = this.state.sortList || this.state.data;

    const filterList = data.filter((d)=>{
      const defaultFilterMethod = (c)=>d[column.property] == c.value;
      return !!filteCondi.filter(column.filterMethod || defaultFilterMethod).length
    });

    this.setState({
      filterList: filteCondi && filteCondi.length ? filterList : data
    });
  }

  flattenHeaderColumn(){
    const { _columns } = this.state;
    const headerLevelColumns = [];
    const leafColumns = [];

    let rescurveColumns = (list)=>{
      list.forEach((item)=>{
        headerLevelColumns[item.level] = headerLevelColumns[item.level] || [];
        headerLevelColumns[item.level].push(item);
        if(item.subColumns instanceof Array){
          rescurveColumns(item.subColumns);
        }else{
          leafColumns.push(item);
        }
      });
    };
    rescurveColumns(_columns);

    return {headerLevelColumns, leafColumns};
  }

  clearSelection() {
    this.refs.mainBody.clearSelect();
    this.refs.header.cancelAllChecked();
  }

  render() {
    let { fit,
      stripe,
      border,
      highlightCurrentRow,
      showSummary,
      sumText,
      getSummaries,
      emptyText
    } = this.props;
    let {
      bodyWidth,
      bodyHeight,
      _columns,
      data,
      fixedLeftColumns,
      fixedRightColumns,
      realTableHeight,
      realTableHeaderHeight,
      scrollY,
      scrollX,
      sortList,
      filterList,
    } = this.state;

    const rootClassName = this.classNames(
      'el-table',
      {
        'el-table--enable-row-hover': !fixedLeftColumns.length && !fixedRightColumns.length,
        'el-table--fit': fit,
        'el-table--striped': stripe,
        'el-table--border': border
      }
    );

    const scrollYWiddth = scrollX ? getScrollBarWidth() : 0;

    data = filterList || sortList || data;

    const flattenColumns = this.flattenHeaderColumn();
    const { leafColumns } = flattenColumns;

    return (
      <div
        ref="root"
        style={this.style()}
        className={this.className(rootClassName)}>
        <div
          ref="headerWrapper"
          className="el-table__header-wrapper">
          <TableHeader
            ref="header"
            isScrollY={scrollY}
            style={{width: bodyWidth}}
            flattenColumns={flattenColumns}
            columns={_columns} />
        </div>

        <div
          style={this.getBodyWrapperStyle()}
          className="el-table__body-wrapper"
          onScroll={this.onScrollBodyWrapper.bind(this)}
          ref="bodyWrapper">
          <TableBody
            ref="mainBody"
            style={{width: bodyWidth}}
            rowClassName={this.props.rowClassName}
            columns={_columns}
            flattenColumns={flattenColumns}
            highlightCurrentRow={highlightCurrentRow}
            data={data} />
        </div>
        {
          !!fixedLeftColumns.length && (
            <div
              className="el-table__fixed"
              ref="fixedWrapper"
              style={{width: calculateFixedWidth(fixedLeftColumns), height: realTableHeight ? (realTableHeight - scrollYWiddth) : ''}}>
              <div className="el-table__fixed-header-wrapper" ref="fixedHeaderWrapper">
                <TableHeader
                  fixed="left"
                  border="border"
                  columns={_columns}
                  flattenColumns={flattenColumns}
                  style={{width: '100%', height: '100%'}} />
              </div>
              <div
                className="el-table__fixed-body-wrapper"
                ref="fixedBodyWrapper"
                style={{top: realTableHeaderHeight, height: bodyHeight ? (bodyHeight - scrollYWiddth) : ''}}>
                {data && data.length &&
                  <TableBody
                    ref="fixedLeftBody"
                    fixed="left"
                    rowClassName={this.props.rowClassName}
                    columns={_columns}
                    data={data}
                    flattenColumns={flattenColumns}
                    highlightCurrentRow={highlightCurrentRow}
                    style={{width: bodyWidth}}>
                  </TableBody>
                }
                {(!data || data.length === 0) &&
                  <div style={{ width: bodyWidth }} className="el-table__empty-block">
                    <span className="el-table__empty-text">{ emptyText || i18n.t('el.table.emptyText') }</span>
                  </div>
                }
              </div>
            </div>)
        }

        <div
          className="el-table__fixed-right"
          ref="rightFixedWrapper"
          style={{width: calculateFixedWidth(fixedRightColumns), height: realTableHeight ? (realTableHeight - scrollYWiddth) : '' ,right: scrollY?getScrollBarWidth() : 0}}>
          <div
            className="el-table__fixed-header-wrapper"
            ref="rightFixedHeaderWrapper">
            <TableHeader
              fixed="right"
              border="border"
              columns={_columns}
              flattenColumns={flattenColumns}
              style={{width: '100%', height: '100%'}} />
          </div>
          <div
            className="el-table__fixed-body-wrapper"
            ref="rightFixedBodyWrapper"
            style={{top: realTableHeaderHeight, height: bodyHeight? (bodyHeight - scrollYWiddth):''}}>
            <TableBody
              ref="fixedRightBody"
              fixed="right"
              rowClassName={this.props.rowClassName}
              columns={_columns}
              data={data}
              flattenColumns={flattenColumns}
              highlightCurrentRow={highlightCurrentRow}
              style={{width: bodyWidth}}>
            </TableBody>
          </div>
        </div>

        {
          showSummary && (
            <TableFooter
              leafColumns={leafColumns}
              sumText={sumText}
              getSummaries={getSummaries}
              data={data} />
          )
        }

        <div
          style={{display: this.state.resizeProxyVisible?"block":"none"}}
          className="el-table__column-resize-proxy"
          ref="resizeProxy">
        </div>

        <div className="el-table__body-scroller">
          <div></div>
        </div>
      </div>
    )
  }
}

Table.childContextTypes = {
  $owerTable: PropTypes.object,
  stripe: PropTypes.bool,
};

Table.defaultProps = {
  columns: [],
  data: [],
  stripe: false,
  border: false,
  fit: true,
  showSummary: false,
  highlightCurrentRow: false
};
