/// <reference path="./definition.d.ts" />

import * as React from 'react';
import classNames from 'classnames';
import Hammer from 'react-hammerjs';
import assign from 'object-assign';
import WebApi from '../ajax/webapi';

const prefix = 'component-View';
class View extends React.Component<TspComponentViewProps, TspComponentViewState> {
  constructor(props: TspComponentViewProps, state: TspComponentViewState) {
    super(props, state);
    this.success = this.success.bind(this);
    this.timeoutCallback = this.timeoutCallback.bind(this);
    this.request = this.request.bind(this);
  }

  public static defaultProps: TspComponentViewProps = {
    delay: 0,
    loadingView: null,
    render: null,
    failView: null,
    timeoutView: null,
    emptyView: null,
    apiConfig: undefined,
    dataKey: 'result'
  };

  public state: TspComponentViewState = {
    status: this.props.apiConfig ? undefined : (this.props.status ? this.props.status : 'complete'),
    updateId: 0
  };

  private data: any;
  /**
   * 接口请求是否完成
   */
  private loadingOver: boolean = false;
  /**
   * setTimeout的返回对象
   */
  // tslint:disable-next-line:typedef
  private timeoutInstance;

  public componentDidMount(): void {
    if (this.props.apiConfig) {
      if (this.props.delay) {
        this.timeoutInstance = setTimeout(() => {
          this.request();
        }, this.props.delay);
      } else {
        this.request();
      }
    }
  }

  public shouldComponentUpdate(nextProps: TspComponentViewProps, nextState: TspComponentViewState): boolean {
    const statusChange = (nextProps.status !== this.props.status) || (this.state.status !== nextState.status);
    const propsReloadIdChange = this.props.reloadId === undefined ? true : (nextProps.reloadId !== this.props.reloadId);
    const stateUpdateIdChange = this.state.updateId !== nextState.updateId;
    const propsRefreshIdChange = nextProps.refreshId !== this.props.refreshId;

    return statusChange || propsReloadIdChange || stateUpdateIdChange || propsRefreshIdChange;
  }

  public componentWillReceiveProps(nextProps: TspComponentViewProps): void {
    // 重载
    if (nextProps.status !== this.props.status) {
      this.setState({
        status: nextProps.status
      });
    }
    if ((nextProps.reloadId !== this.props.reloadId) && this.props.apiConfig) {
      this.request(nextProps);
    }
    if (nextProps.refreshId !== this.props.refreshId) {
      this.setState({
        updateId: this.state.updateId + 1
      });
    }
  }

  public componentWillUnmount(): void {
    clearTimeout(this.timeoutInstance);
  }

  /**
   * 根据状态渲染视图
   */
  public statusRender(): JSX.Element {
    switch (this.state.status) {
      case 'loading': return this.props.loadingView;
      case 'complete': return this.props.render(this.data);
      // case 'fail': return this.props.failView;
      case 'fail': return this.timeoutView();
      case 'timeout': return this.timeoutView();
      case 'empty': return this.props.emptyView;
      default: return null;
    }
  }

  /**
   * 超时视图，点击可刷新
   */
  public timeoutView(): JSX.Element {
    return (
      <Hammer onTap={() => this.request()}>
        {this.props.timeoutView}
      </Hammer>
    );
  }

  /**
   * 发起请求
   */
  public request(props: TspComponentViewProps = this.props): void {
    const params = assign({}, props.apiConfig, {
      success: this.success,
      timeoutCallback: this.timeoutCallback,
    });
    this.loadingOver = false;

    this.props.request(params);
    this.timeoutInstance = setTimeout(() => {
      if (!this.loadingOver) {
        this.setState({
          status: 'loading'
        });
      }
    }, 300);
  }

  /**
   * 请求成功的函数
   */
  public success(data: any, status: boolean): void {
    let temp;
    if (status) {
      this.data = data[this.props.dataKey];
      if (this.data) {
        if (this.data.length === undefined || this.data.length) {
          temp = 'complete';
        } else {
          temp = 'empty';
        }
      } else {
        temp = 'empty';
      }
    } else {
      temp = 'fail';
    }

    this.loadingOver = true;
    this.setState({
      status: temp,
      updateId: this.state.updateId + 1
    });
  }

  public timeoutCallback(): void {
    this.data = undefined;
    this.setState({
      status: 'timeout',
      updateId: this.state.updateId + 1
    });
  }

  public render(): JSX.Element {
    return (
      <div
        className={classNames({
          [prefix]: true,
          [this.props.className]: this.props.className
        })}
      >
        {this.statusRender()}
      </div>
    );
  }
}

export default View;