import {
    INPUT_START,
    INPUT_MOVE,
    INPUT_END,
    INPUT_CANCEL,
    INPUT_TYPE_TOUCH
} from '../inputjs/input-consts';
import Input from '../inputjs/input-constructor';
import toArray from '../utils/to-array';
import uniqueArray from '../utils/unique-array';

const SINGLE_TOUCH_INPUT_MAP = {
  touchstart: INPUT_START,
  touchmove: INPUT_MOVE,
  touchend: INPUT_END,
  touchcancel: INPUT_CANCEL
};

const SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
const SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';

/**
 * @private
 * Touch events input
 * @constructor
 * @extends Input
 */
export default class SingleTouchInput extends Input {
  constructor() {
    var proto = SingleTouchInput.prototype;
    proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
    proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;

    super(...arguments);
    this.started = false;
  }

  handler(ev) {
    let type = SINGLE_TOUCH_INPUT_MAP[ev.type];

    // should we handle the touch events?
    if (type === INPUT_START) {
      this.started = true;
    }

    if (!this.started) {
      return;
    }

    let touches = normalizeSingleTouches.call(this, ev, type);

    // when done, reset the started state
    if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
      this.started = false;
    }

    this.callback(this.manager, type, {
      pointers: touches[0],
      changedPointers: touches[1],
      pointerType: INPUT_TYPE_TOUCH,
      srcEvent: ev
    });
  }
}

/**
 * @private
 * @this {TouchInput}
 * @param {Object} ev
 * @param {Number} type flag
 * @returns {undefined|Array} [all, changed]
 */
function normalizeSingleTouches(ev, type) {
  let all = toArray(ev.touches);
  let changed = toArray(ev.changedTouches);

  if (type & (INPUT_END | INPUT_CANCEL)) {
    all = uniqueArray(all.concat(changed), 'identifier', true);
  }

  return [all, changed];
}
