/// <reference path="./definition.d.ts" />

import * as React from 'react';
import classNames from 'classnames';
import assign from 'object-assign';
import Hammer from 'react-hammerjs';

const prefix = 'tsp-component-ListView';
const distance = 1000;
class ListView extends React.Component<TspComponentListViewProps, TspComponentListViewState> {
  constructor(props: TspComponentListViewProps, state: TspComponentListViewState) {
    super(props, state);
    this.onTouchmove = this.onTouchmove.bind(this);
    this.success = this.success.bind(this);
    this.timeoutCallback = this.timeoutCallback.bind(this);
  }

  public static defaultProps: TspComponentListViewProps = {
    // delay: 0,
    request: () => null,
    params: undefined,
    rowRender: () => null,
    emptyView: null,
    failView: null,
    timeoutView: null,
    loadingView: null,
    pageStart: 1,
    dataKey:  ['result']
  };

  public state: TspComponentListViewState = {
    render: []
  };

  /**
   * 数据源字段
   */
  public static dataKey: string[];
  /**
   * 页数字段
   */
  public static pageKey: string;
  /**
   * 每页条数字段
   */
  public static pageSizeKey: string;

  /**
   * 容器元素
   */
  private elem: HTMLElement;
  /**
   * 加载数据时底部提示文字
   */
  private loadingElem: HTMLElement;
  /**
   * setTimeout的返回对象
   */
  // tslint:disable-next-line:typedef
  private timeoutInstance;
  /**
   * 用于渲染的数据
   */
  private data: any[] = [];
  /**
   * 来自于接口的源数据
   */
  private sourceData: any[] = [];
  /**
   * 数据源字段
   */
  private get dataKey(): string[] {
    return this.props.dataKey ? this.props.dataKey : ListView.dataKey;
  }
  /**
   * 页数字段
   */
  private get pageKey(): string {
    return this.props.pageKey ? this.props.pageKey : ListView.pageKey;
  }
  /**
   * 每页条数字段
   */
  private get pageSizeKey(): string {
    return this.props.pageSizeKey ? this.props.pageSizeKey : ListView.pageSizeKey;
  }
  /**
   * 页数
   */
  private page: number;
  /**
   * 每页条数
   */
  private pageSize: number;
  /**
   * 加载状态
   */
  private status: TspComponentListViewStatus;
  /**
   * 滚动容器
   */
  private scrollContainerElem: HTMLElement;
  /**
   * 节流，每250毫秒触发一次，true: 可以触发，false: 不能触发
   */
  private throttle: boolean = true;
  /**
   * 节流setTimeout实例
   */
  // tslint:disable-next-line:typedef
  private throttleTimeoutInstance;
  /**
   * 加载中状态是否结束
   */
  private loadingOver: boolean;

  public componentWillUnmount(): void {
    this.elem.removeEventListener('touchmove', this.onTouchmove);
    clearTimeout(this.timeoutInstance);
    clearTimeout(this.throttleTimeoutInstance);
  }

  public componentDidMount(): void {
    this.elem = this.refs.elem as HTMLElement;
    this.loadingElem = this.refs.loading as HTMLElement;

    if (this.props.scrollContainerId) {
      this.scrollContainerElem = document.getElementById(this.props.scrollContainerId);
    }
    this.page = this.props.params.params[this.pageKey];
    this.pageSize = this.props.params.params[this.pageSizeKey];

    this.setState({ render: this.props.loadingView });
    this.elem.addEventListener('touchmove', this.onTouchmove);

    if (this.props.delay) {
      this.timeoutInstance = setTimeout(() => {
        this.request();
      }, this.props.delay);
    } else {
      this.request();
    }
  }

  public componentWillReceiveProps(nextProps: TspComponentListViewProps): void {
    // 重载
    if (nextProps.reloadId !== this.props.reloadId) {
      this.page = nextProps.pageStart;
      this.data = [];
      this.sourceData = [];
      this.status = 'loading';
      this.setState({ render: nextProps.loadingView });
      this.request(nextProps.params);
    }
    // 刷新当前
    if (this.props.refreshId !== nextProps.refreshId) {
      this.setState({
        render: this.dataRender(nextProps)
      });
    }
  }

  /**
   * 滑动事件
   */
  public onTouchmove(e: any): void {
    if (this.status !== 'complete' || !this.loadingOver) {
      return;
    }
    if (this.throttle) {
      this.throttle = false;
    } else {
      return;
    }
    let offsetTop;
    let scrollHeight;
    if (this.props.scrollContainerId) {
      offsetTop = this.scrollContainerElem.offsetTop;
      scrollHeight = this.scrollContainerElem.offsetHeight;
    } else {
      offsetTop = document.body.scrollTop;
      scrollHeight = document.body.scrollHeight;
    }

    this.throttleTimeoutInstance = setTimeout(() => {
      this.throttle = true;
    }, 250);

    if (scrollHeight - offsetTop > distance) {
      return;
    } else {
      this.request();
    }
  }

  /**
   * 发起请求
   */
  public request(sendParams: TspComponentAjaxPostOption = this.props.params): void {
    const requestParams = assign({}, sendParams.params, {
      [this.pageKey]: this.page
    });
    const params = assign({}, sendParams, {
      params: requestParams,
      success: this.success,
      timeoutCallback: this.timeoutCallback,
    });
    this.loadingOver = false;

    this.props.request(params);
    this.timeoutInstance = setTimeout(() => {
      if (!this.loadingOver) {
        this.status = 'loading';
        if (this.data.length) {
          this.loadingElem.style.display = 'block';
        } else {
          this.setState({ render: this.props.loadingView });
        }
      }
    }, 300);
  }

  /**
   * 请求成功的函数
   */
  public success(data: any, status: boolean): void {
    if (status) {
      let temp;
      const firstKey = this.dataKey[0];
      const secondKey = this.dataKey[1];
      const tempData = firstKey && secondKey && this.sourceData ? this.sourceData[secondKey] : undefined;
      if (tempData) {
        this.sourceData = assign({}, this.sourceData, data, {
          [secondKey]: this.sourceData[secondKey].concat(data[firstKey][secondKey])
        });
      } else {
        if (firstKey && secondKey) {
          this.sourceData = data[firstKey];
        } else {
          this.sourceData = this.sourceData ? this.sourceData.concat(data[firstKey]) : data[firstKey];
        }
      }

      for (let i = 0; i < this.dataKey.length; i++) {
        if (i === 0) {
          temp = data[this.dataKey[0]];
        } else if (i === 1) {
          temp = data[this.dataKey[0]][this.dataKey[1]];
        }
      }

      this.data = this.data.concat(temp);

      if (temp.length) {
        this.status = 'complete';
      } else if (this.data.length && temp.length < this.pageSize) {
        this.status = 'over';
      } else if (!this.data.length && !temp.length) {
        this.status = 'empty';
      } else {
        this.status = 'fail';
      }
    } else {
      this.status = 'fail';
    }

    this.page++;
    this.loadingElem.style.display = 'none';
    this.loadingOver = true;
    this.setStateRender();
  }

  /**
   * 设置state的render
   */
  public setStateRender(): void {
    const length = this.data.length;
    let temp = [];

    if (this.status === 'complete') {
      temp = this.dataRender();
    } else if (this.status === 'empty') {
      temp = this.props.emptyView;
    } else if (this.status === 'over') {
      temp = this.state.render;
    } else if (!length && this.status === 'fail') {
      // temp = this.props.failView;
      temp = this.timeoutView();
    } else if (this.status === 'timeout') {
      temp = this.timeoutView();
    }

    this.setState({
      render: temp
    });
  }

  /**
   * 超时视图，点击可刷新
   */
  public timeoutView(): any {
    return (
      <Hammer onTap={() => this.request()}>
        {this.props.timeoutView}
      </Hammer>
    );
  }

  /**
   * 数据渲染
   */
  public dataRender(props: TspComponentListViewProps = this.props): any[] {
    const length = this.data.length;
    const temp = [];
    let i = 0;

    for (i; i < length; i++) {
      if (props.filter) {
        if (props.filter(this.data[i])) {
          temp.push(props.rowRender(this.data[i], i, this.data));
        }
      } else {
        temp.push(props.rowRender(this.data[i], i, this.data));
      }
    }

    return temp;
  }

  public timeoutCallback(): void {
    const length = this.data.length;

    if (!length) {
      this.status = 'timeout';
      this.setState({
        render: this.timeoutView()
      });
    } else {
      this.loadingOver = true;
      this.status = 'complete';
    }
    this.loadingElem.style.display = 'none';
  }

  public render(): JSX.Element {
    const successExtendsViewShowStauts = this.status === 'complete' || this.status === 'over';
    const completeExtendsViewShowStauts = this.status !== 'timeout';
    return (
      <div
        className={classNames({
          [prefix]: true,
          [this.props.className]: this.props.className
        })}
        ref="elem"
      >
        {successExtendsViewShowStauts && this.props.successBeforeView ? this.props.successBeforeView(this.sourceData) : null}
        {completeExtendsViewShowStauts && this.props.completeBeforeView ? this.props.completeBeforeView(this.sourceData) : null}
        {this.status === 'complete' ? (
          this.state.render.map((value) => value)
        ) : (
          this.state.render
        )}
        <div className={`${prefix}-loading`} ref="loading"></div>
        {successExtendsViewShowStauts && this.props.successAfterView ? this.props.successAfterView(this.sourceData) : null}
      </div>
    );
  }
}

export default ListView;