/// <reference path="./definition.d.ts" />

import * as React from 'react';
import { setTranslate } from '../util/animation';

const prefix = 'tsp-component-slider';
class Silder {
  constructor(params?: TspComponentSliderConstructorParams) {
    this.sliderElem = params.sliderElem;
    this.containerElem = params.containerElem;
    this.count = params.count;
    this.direction = params.direction;
    // this.swipeable = params.swipeable || true;
    this.width = params.width;
    this.height = params.height;
    this.selectedIndex = params.selectedIndex;
    this.afterChangeIndexs = {
      beforeSelectIndex: this.selectedIndex,
      afterSelectedIndex: this.selectedIndex
    };

    this.panStart = this.panStart.bind(this);
    this.panMove = this.panMove.bind(this);
    this.panEnd = this.panEnd.bind(this);
    this.sliderMove = this.sliderMove.bind(this);
    this.getMoveBeforePosition = this.getMoveBeforePosition.bind(this);
    this.setMoveAfterSelectedIndex = this.setMoveAfterSelectedIndex.bind(this);
    this.getPanEndDistance = this.getPanEndDistance.bind(this);
    this.addPanEndClass = this.addPanEndClass.bind(this);
    this.removePanEndClass = this.removePanEndClass.bind(this);
  }

  /**
   * 滑动方向
   */
  private direction: TspComponentSliderModel;
  /**
   * 宽度
   */
  private width: number;
  /**
   * 高度
   */
  private height: number;
  /**
   * 当前索引
   */
  public selectedIndex: number;
  /**
   * 滑块个数
   */
  public count: number;
  /**
   * 滑动完成后的回调返回的索引值
   */
  public afterChangeIndexs: TspComponentSliderAfterChangeReturn;
  /**
   * 滑动是否结束
   */
  public isPanEnd: boolean = true;
  /**
   * 滑动容器
   */
  public sliderElem: HTMLElement;
  /**
   * 组件顶层容器
   */
  public containerElem: HTMLElement;
  /**
   * 滑动时移动的距离
   */
  public panDistance: number;

  /**
   * 是否超过临界值
   */
  private get isCritical(): boolean {
    const model = this.direction === 'horizontal' ? 'width' : 'height';
    return this[model] * 0.25 <= this.panDistance;
  }
  /**
   * 标量，用于计算位移
   */
  private get scalar(): [number, string] {
    return this.direction === 'horizontal' ? [this.width, 'deltaX'] : [this.height, 'deltaY'];
  }
  /**
   * 开始滑动
   */
  public panStart(): void {
    this.isPanEnd = false;
    this.removePanEndClass();
  }

  /**
   * 滑动中
   */
  public panMove(evt: TspComponentSliderEvt): void {
    // 禁止滑动就不执行下面
    if (this.isPanEnd) {
      return;
    }

    if (evt.distance < this.width * 0.9) {
      const position = this.getMoveBeforePosition();
      const moveDistance = {
        x: position.x ? position.x + evt.deltaX : 0,
        y: position.y ? position.y + evt.deltaY : 0
      };
      this.panDistance = evt.distance;
      this.sliderMove(moveDistance.x , moveDistance.y);
    } else {
      this.panEnd(evt);
    }
  }

  /**
   * 滑动结束
   */
  public panEnd(evt: TspComponentSliderEvt): void {
    // 禁止滑动就不执行下面, onPanEnd方法是否已触发
    if (this.isPanEnd) {
      return;
    }

    const beforeSelectIndex = this.selectedIndex;
    const isChangeSlectedIndex = this.setMoveAfterSelectedIndex(evt);
    const position = this.getPanEndDistance(evt, isChangeSlectedIndex);

    this.isPanEnd = true;
    this.afterChangeIndexs = {
      beforeSelectIndex,
      afterSelectedIndex: this.selectedIndex
    };
    this.addPanEndClass();
    this.sliderMove(position.x, position.y);
  }

  /**
   * 改变索引
   */
  public onChangeSelectedIndex(evt: TspComponentSliderEvt, selectedIndex: number): void {
    const position = this.getPanEndDistance(evt, true);
    const children = this.sliderElem.children;

    this.afterChangeIndexs = {
      beforeSelectIndex: this.selectedIndex,
      afterSelectedIndex: selectedIndex
    };
    this.selectedIndex = selectedIndex;

    this.addPanEndClass();
    this.sliderMove(position.x, position.y);
  }

  /**
   * 移动滑块容器
   */
  public sliderMove(x: number, y: number): void {
    setTranslate(this.sliderElem, x, y);
  }

  /**
   * 获取移动前的初始化位置
   */
  public getMoveBeforePosition(): { x: number, y: number } {
    return {
      x: this.direction === 'horizontal' ? -this.width : 0,
      y: this.direction === 'vertical' ? -this.height : 0
    };
  }

  /**
   * 设置移动后的索引值,如果索引改变为ture
   */
  public setMoveAfterSelectedIndex(evt: TspComponentSliderEvt): boolean {

    if (!this.isCritical) {
      return false;
    }
    const count = this.count - 1;

    if (evt[this.scalar[1]] < 0) {
      this.selectedIndex = this.selectedIndex === count ? 0 : this.selectedIndex + 1;
    } else {
      this.selectedIndex = this.selectedIndex === 0 ? count : this.selectedIndex - 1;
    }

    return true;
  }

  /**
   * 获取滑动完成后需要移动的距离
   */
  public getPanEndDistance(evt: TspComponentSliderEvt, isChangeSlectedIndex: boolean): { x: number, y: number } {
    let value = -this.scalar[0];
    if (isChangeSlectedIndex) {
      if (evt[this.scalar[1]] < 0) {
        value = 2 * -this.scalar[0];
      } else {
        value = 0;
      }
    }

    return {
      x: this.direction === 'horizontal' ? value : 0,
      y: this.direction === 'vertical' ? value : 0
    };
  }

  /**
   * 添加panend样式
   */
  public addPanEndClass(): void {
    this.sliderElem.classList.add(`${prefix}-panend`);
  }
  /**
   * 移除panend样式
   */
  public removePanEndClass(): void {
    this.sliderElem.classList.remove(`${prefix}-panend`);
  }
}

export default Silder;