/// <reference path="./definition.d.ts" />

import * as React from 'react';
import Hammer from 'react-hammerjs';
import classNames from 'classnames';
import { getUrlParams } from '../util/router';
import Exception from '../exception';

const prefix = 'tsp-component-ImgView';
class ImgView extends React.Component<TspComponentImgViewProps, any> {
  constructor(props: TspComponentImgViewProps, state: any) {
    super(props, state);

    this.onLoad = this.onLoad.bind(this);
    this.onError = this.onError.bind(this);
    this.onTap = this.onTap.bind(this);
  }

  public static defaultProps: TspComponentImgViewProps = {
    src: '',
    loading: '',
    fail: '',
    timeout: ''
  };

  /**
   * 加载图片的元素
   */
  private elem: HTMLElement;
  /**
   * img对象
   */
  private img: HTMLImageElement;
  /**
   * 图片加载状态
   */
  private status: TspComponentImgViewStatus = 'loading';
  /**
   * setTimeout 实例，用于清除定时器
   */
  private timeoutInstance: number;
  /**
   * 是否销毁组件
   */
  private isDestory: boolean;

  public componentWillUnmount(): void {
    if (this.img) {
      this.img.src = '';
      this.img = null;
      this.isDestory = true;
    }
    clearTimeout(this.timeoutInstance);
  }

  public componentDidMount(): void {
    const src = this.props.src ? this.props.src : this.props.default;
    this.elem = this.refs.elem as HTMLElement;
    this.imgInitial(src);
  }

  public componentWillReceiveProps(nextProps: TspComponentImgViewProps): void {
    if (this.props.src !== nextProps.src && !this.props.default) {
      this.setImgSrc(nextProps.src);
    } else if (!this.props.src && this.props.default) {
      this.setImgSrc(nextProps.default);
    }
  }

  /**
   * 图片加载成功
   */
  public onLoad(): void {
    this.setStatus('complete');
  }

  /**
   * 图片加载失败
   */
  public onError(): void {
    if (!this.isDestory) {
      this.setStatus('fail');
    }
  }

  /**
   * 图片点击事件
   */
  public onTap(): void {
    if (this.status === 'timeout') {
      const time = new Date().getTime();
      let src = this.props.src;

      if (getUrlParams(this.props.src).search) {
        src += `&componentLoadTimestamp=${time}`;
      } else {
        src += `?componentLoadTimestamp=${time}`;
      }
      this.imgInitial(src);
      this.status = 'loading';
    } else if (this.props.onClick) {
      this.props.onClick();
    }
  }

  /**
   * img对象初始化
   */
  public imgInitial(src: string): void {
    this.img = new Image();
    this.img.onload = this.onLoad;
    this.img.onerror = this.onError;
    this.setImgSrc(src);
  }

  public setStatus(status: TspComponentImgViewStatus): void {
    const exceptionParams = {
      errorType: undefined,
      url: this.props.src,
      content: `id: ${this.props.id ? this.props.id : ''};`,
      details: JSON.stringify(this.props.describe)
    };
    this.status = status;
    switch (status) {
      case 'loading':
        this.elem.style.backgroundImage = `url(${this.props.loading})`;
        this.elem.classList.remove(`${prefix}-timeout`);
        this.elem.classList.add(`${prefix}-loading`);
        break;
      case 'complete':
        this.elem.style.backgroundImage = `url(${this.props.src ? this.props.src : this.props.default})`;
        this.elem.classList.remove(`${prefix}-loading`);
        this.elem.classList.add(`${prefix}-complete`);
        this.elem.dataset.trackurl = this.props.src;
        break;
      case 'timeout':
        this.elem.style.backgroundImage = `url(${this.props.timeout})`;
        this.elem.classList.remove(`${prefix}-loading`);
        this.elem.classList.add(`${prefix}-timeout`);
        exceptionParams.errorType = 5;
        Exception.send(exceptionParams);
        break;
      case 'fail':
        this.elem.style.backgroundImage = `url(${this.props.fail})`;
        this.elem.classList.remove(`${prefix}-loading`);
        this.elem.classList.add(`${prefix}-fail`);
        exceptionParams.errorType = 4;
        Exception.send(exceptionParams);
        break;
      default: break;
    }
    if (this.props.onStatusChange) {
      this.props.onStatusChange(status);
    }
  }

  /**
   * 设置图片地址
   */
  public setImgSrc(src: string): void {
    if (src) {
      clearTimeout(this.timeoutInstance);
      this.img.src = src;
      this.timeoutInstance = setTimeout(() => {
        if (this.status === 'loading') {
          this.setStatus('loading');
          if (this.props.timeout) {
            this.timeoutInstance = setTimeout(() => {
              if (this.status === 'loading') {
                this.img.onerror = null;
                this.img.src = '';
                this.img = null;
                this.setStatus('timeout');
              }
            }, 15000);
          }
        }
      }, 100);
    } else {
      this.setStatus('loading');
    }
  }

  public render(): JSX.Element {
    const classname = classNames({
      [prefix]: true,
      [this.props.className]: this.props.className
    });

    return (
      <Hammer onTap={this.onTap}>
        <div className={classname} id={this.props.id ? this.props.id : ''} ref="elem" />
      </Hammer>
    );
  }
}

export default ImgView;
