/// <reference path="./definition.d.ts" />

import * as React from 'react';
import { popupOpen, popupClose } from '../popup';
import { setTranslate } from '../util/animation';
import FormCore from '../form/core';

const prefix = 'tsp-component-Picker';
const coefficient = 102;
class Picker  {
  constructor(params: TspComponentPickerCoreParams) {
    this.id = params.id;
    this.cascade = params.cascade || false;
    this.value = params.defaultValue;
    this.data = params.data;
    this.onOk = params.onOk;
    this.sliderElem = params.sliderElem;
    this.containerElem = params.containerElem;
    this.labelElem = params.labelElem;
    this.formatLabel = params.formatLabel;
    this.required = params.required;

    this.panStart = this.panStart.bind(this);
    this.pan = this.pan.bind(this);
    this.panEnd = this.panEnd.bind(this);
    this.ok = this.ok.bind(this);
    this.cancel = this.cancel.bind(this);
    this.open = this.open.bind(this);
    this.transitionEnd = this.transitionEnd.bind(this);
    this.labelElem.innerText = params.defaultLabel || '请选择';
  }

  private id: string;
  /**
   * FormCore 实例
   */
  private formCore: FormCore;
  /**
   * 该字段必选提示文字
   */
  private required: string;
  /**
   * 是否级联
   */
  private cascade: boolean;
  /**
   * 值, 格式[value1, value2, value3], 对应数据源的N级value或索引
   */
  private value: TspComponentPickerValues[];
  /**
   * 改变之后触发
   */
  private onOk: (selected: TspComponentPickerValues[]) => void;
  /**
   * 记录当前拖动的元素translateY的值
   */
  private translateY: number[] = [];
  /**
   * 移动开始之前的索引
   */
  private moveStartBeforeValueIndex: number;
  /**
   * 移动中上一个选中的索引
   */
  private moveingPrevValueIndex: number;
  /**
   * 格式化渲染文本
   */
  private formatLabel: (selected: TspComponentPickerValues[]) => string;
  /**
   * 拖动是否结束
   */
  public isPanEnd: boolean = true;
  /**
   * 触摸事件在哪个列上响应
   */
  public touchElementCol: number = 0;
  /**
   * 滑块元素
   */
  public sliderElem: HTMLElement;
  /**
   * 主容器Element
   */
  public containerElem: HTMLElement;
  /**
   * 文本Element
   */
  public labelElem: HTMLElement;
  /**
   * 被选中的项
   */
  public selected: TspComponentPickerValues[] = [];
  /**
   * 数据源
   */
  public data: TspComponentPickerDataSource[][];
  /**
   * 是否已出发onTransitionEnd
   */
  public isTransitionEnd: boolean = false;

  /**
   * 初始化
   */
  public init(): void {
    for (let i = 0; i < this.data.length; i++) {
      if (this.value) {
        this.selected.push(this.value[i]);
      } else {
        this.selected.push({
          index: 0
        });
      }
      this.renderCol(this.data[i], i, 'init');
    }

    this.formCore = new FormCore({
      elem: this.containerElem,
      required: this.required,
      defaultValue: this.value.map((value) => value.value).join()
    });
    this.setLabel();
    this.setElemValue();
  }

  /**
   * 开始拖动
   */
  public panStart(evt: TspComponentSliderEvt): void {
    this.touchElementCol = this.getTouchElementCol(evt);
    if (this.touchElementCol !== undefined) {
      this.isPanEnd = false;
      this.moveStartBeforeValueIndex = this.getValueIndex(this.touchElementCol, this.selected);
      this.moveingPrevValueIndex = this.moveStartBeforeValueIndex;
      this.isTransitionEnd = false;
      this.removePanEndClass(this.touchElementCol);
    }
  }

  /**
   * 拖动中
   */
  public pan(evt: TspComponentSliderEvt): void {
    if (!this.isPanEnd) {
      const position = this.getMoveBeforePosition(this.touchElementCol, this.moveStartBeforeValueIndex);
      const moveY = this.getMoveDistance(this.touchElementCol, position, evt.deltaY);
      const nowValueIndex = this.getSelectedIndexByMoveY(this.touchElementCol, moveY);

      this.moveingPrevValueIndex = this.setCurrentStyle(this.touchElementCol, this.moveingPrevValueIndex, nowValueIndex);
      this.sliderMove(this.touchElementCol , moveY);
    }
  }

  /**
   * 拖动结束后
   */
  public panEnd(evt: TspComponentSliderEvt): void {
    if (!this.isPanEnd) {
      const position = this.getMoveBeforePosition(this.touchElementCol, this.moveingPrevValueIndex);
      this.isPanEnd = true;

      // this.containerElem.classList.add('tsp-compoent-slider-disabled');
      this.setSelected(this.touchElementCol, this.moveingPrevValueIndex);
      this.addPanEndClass(this.touchElementCol);
      this.sliderMove(this.touchElementCol, position);
    }
  }

  /**
   * 监听translate完成事件
   */
  public transitionEnd(timeoutInstance: number): void {
    this.isTransitionEnd = true;
    this.removePanEndClass(this.touchElementCol);
    // this.containerElem.classList.remove('tsp-compoent-slider-disabled');
    clearTimeout(timeoutInstance);
  }

  /**
   * 确定
   */
  public ok(): void {
    popupClose(this.id);
    this.setLabel();
    this.setElemValue();
    if (this.onOk) {
      this.onOk(this.selected);
    }
  }
  /**
   * 取消
   */
  public cancel(): void {
    const children = this.sliderElem.children;
    for (let i = 0; i < this.data.length; i++) {
      children[i].children[this.getValueIndex(i, this.selected)].classList.remove(`${prefix}-body-col-item-current`);
      children[i].children[this.getValueIndex(i, this.selected)].classList.add(`${prefix}-body-col-item-current`);
      if (this.value) {
        this.selected[i] = this.value[i];
      }
    }
    popupClose(this.id);
  }

  /**
   * 打开
   */
  public open(): void {
    for (let i = 0; i < this.data.length; i++) {
      this.pickerTranslateInitial(i, this.getValueIndex(i, this.selected));
    }
    popupOpen(this.id);
  }

  /**
   * 设置显示的文本
   */
  public setLabel(): void {
    if (this.formatLabel) {
      this.labelElem.textContent = this.formatLabel(this.selected);
    } else {
      let label = '';
      for (let i = 0; i < this.selected.length; i++) {
        if (this.selected[i].value !== undefined) {
          label += this.selected[i].label;
        }
      }
      if (label !== '' && label !== 'undefined') {
        this.labelElem.textContent = label;
      }
    }
  }

  /**
   * 设置元素element dataset.value
   */
  public setElemValue(): void {
    const value = [];
    for (let i = 0; i < this.selected.length; i++) {
      value.push(this.selected[i].value);
    }
    this.formCore.elem.dataset.value = value.join();
  }

  /**
   * 将待分配的children移动到排列的位置
   */
  public pickerTranslateInitial(col: number, selectedIndex: number): void {
    const elem = this.sliderElem.children[col];
    const position = this.getMoveBeforePosition(col, selectedIndex);
    // const oldIndex = this.getValueIndex(col, this.selected);
    const length = elem.children.length;
    this.translateY[col] = position;

    for (let i = 0; i < length; i++) {
      elem.children[i]['classList'].remove(`${prefix}-body-col-item-current`);
    }
    this.setSelected(col, selectedIndex);
    elem.children[selectedIndex]['classList'].add(`${prefix}-body-col-item-current`);
    setTranslate(elem as HTMLElement, 0, position);
  }

  /**
   * 递归获取value的children
   */
  // public getValueChildren(value: TspComponentPickerValues[], col: number, index: number = 0): TspComponentPickerValues[] {
  //   if (index >= col) {
  //     return value;
  //   } else {
  //    return this.getValueChildren(value[this.selected[index].index].children, col, index + 1);
  //   }
  // }

  /**
   * 创建每列子项的元素
   */
  public createColItemElement(data: TspComponentPickerDataSource[]): HTMLElement[] {
    const elem = document.createElement('div');
    const tempArray = [];
    const length = data.length;
    let i = data.length;

    elem.classList.add(`${prefix}-body-col-item`);
    for (i = 0; i < length; i++) {
      const temp = elem.cloneNode(false);
      temp.textContent = data[i].label.toString();
      tempArray.push(temp);
    }

    return tempArray;
  }

  /**
   * 获取value在data中的索引
   */
  public getValueIndex(col: number, value: TspComponentPickerValues[] = this.value): number {
    let selectedIndex = 0;

    if (!value) {
      return;
    }

    if (value[col].index !== undefined) {
      selectedIndex = value[col].index;
    } else if (value[col].value !== undefined) {
      const length = this.data[col].length;
      let i;
      for (i = 0; i < length; i++) {
        if (value[col].value === this.data[col][i].value) {
          selectedIndex = i;
          break;
        }
      }
    }

    return selectedIndex;
  }

  /**
   * 获取触摸事件在哪个列上响应
   */
  public getTouchElementCol(evt: TspComponentSliderEvt): number {
    const col = evt.target.parentNode['dataset'].col;
    if (col) {
      return parseInt(col);
    } else {
      return undefined;
    }
  }

  /**
   * 添加panend样式
   */
  public addPanEndClass(col: number): void {
    this.sliderElem.children[col].classList.add('tsp-component-slider-panend');
  }

  /**
   * 移除panend样式
   */
  public removePanEndClass(col: number): void {
    if (this.sliderElem.children[col]) {
      this.sliderElem.children[col].classList.remove('tsp-component-slider-panend');
    }
  }

  /**
   * 获取移动前的初始化位置
   */
  public getMoveBeforePosition(col: number, selectedIndex: number): number {
    return selectedIndex * -34 + coefficient;
  }

  /**
   * 获取移动的距离
   */
  public getMoveDistance(col: number, position: number, deltaY: number): number {
    const length = (this.data[col].length - 1) * -34 + coefficient;
    const distance = position + deltaY;
    const symbol = deltaY < 0 ? -1 : 1;

    if (distance > coefficient || distance < length) {
      return this.translateY[col] + symbol * 0.25;
    }

    return distance;
  }
  /**
   * 移动滑块容器
   */
  public sliderMove(col: number, y: number): void {
    this.translateY[col] = y;
    setTranslate(this.sliderElem.children[col] as HTMLElement, 0, y);
  }

  /**
   * 根据移动距离计算索引
   */
  public getSelectedIndexByMoveY(col: number, moveY: number): number {
    const nowValueIndex = -Math.round((moveY - coefficient) / 34);
    const count = this.data[col].length - 1;

    if (nowValueIndex >= count) {
      return count;
    } else if (nowValueIndex <= 0) {
      return 0;
    }
    return nowValueIndex;
  }

  /**
   * 设置选中的item样式
   */
  public setCurrentStyle(col: number, oldIndex: number, nowIndex: number): number {
    if (oldIndex !== nowIndex) {
      const elem = this.sliderElem.children[col].children;
      elem[oldIndex].classList.remove(`${prefix}-body-col-item-current`);
      elem[nowIndex].classList.add(`${prefix}-body-col-item-current`);
    }
    return nowIndex;
  }

  /**
   * 设置选中的值
   */
  public setSelected(col: number, selectedIndex: number): void {
    const data = this.data[col];
    this.selected[col] = {
      value: data[selectedIndex].value,
      index: selectedIndex,
      label: data[selectedIndex].label
    };
  }

  /**
   * 渲染列
   */
  public renderCol(data: TspComponentPickerDataSource[], col: number, type: string): void {
    const fragment = document.createDocumentFragment();
    const elems = this.createColItemElement(data);
    const wrap = document.createElement('div');
    const length = elems.length;
    let i;

    for (i = 0; i < length; i++) {
      fragment.appendChild(elems[i]);
    }
    wrap.classList.add(`${prefix}-body-col`);
    wrap.dataset.col = col.toString();
    wrap.appendChild(fragment);
    if (type === 'init') {
      this.sliderElem.appendChild(wrap);
    } else {
      this.sliderElem.replaceChild(wrap, this.sliderElem.children[col]);
    }
  }

  public componentWillReceiveProps(props: TspComponentDatePickerProps, nextProps: TspComponentDatePickerProps): void {
    if (props.updateId !== nextProps.updateId || props.defaultLabel !== nextProps.defaultLabel) {
      if (nextProps['data']) {
        this.data = nextProps['data'];
      }
      this.sliderElem.innerHTML = '';
      for (let i = 0; i < nextProps.defaultValue.length; i++) {
        const defaultValue = nextProps.defaultValue[i].value;
        this.selected[i] = {
          value: defaultValue === undefined || defaultValue === null ? undefined : defaultValue.toString(),
          index: undefined,
          label: props.changeLabel && nextProps.defaultValue[i].value !== undefined ? nextProps.defaultValue[i].label : undefined,
        };
        this.renderCol(this.data[i], i, 'init');
      }
      this.setLabel();
      this.setElemValue();
    }
  }
}

export default Picker;