import * as THREE from 'three';
import { Utils } from 'cal';
import createListener from 'touch-events';
import bowser from 'bowser';
import { convertEvent, isMouseEvent } from '../utils/pointerUtils.js';

const events = ['wheel', 'tap', 'dragstart', 'drag', 'dragend', 'seconddragstart', 'seconddrag',
  'seconddragend', 'multitouchstart', 'multitouch', 'multitouchend'];

export class EventScene extends THREE.Scene {
  constructor(domElement) {
    super();

    if (domElement) this.setCanvas(domElement);
  }
  _addEventsListeners() {
    for (let i = 0; i < events.length; i ++) {
      const eventType = events[i];
      this._eventDispatcher.addEventListener(eventType, this.convertEvent);
    }
    this._domElement.addEventListener('contextmenu', this.contextMenu);
  }
  _removeEventListeners() {
    for (let i = 0; i < events.length; i ++) {
      const eventType = events[i];
      this._eventDispatcher.removeEventListener(eventType, this.convertEvent);
    }
    this._domElement.removeEventListener('contextmenu', this.contextMenu);
  }
  contextMenu(event) {
    event.preventDefault();
  }
  convertEvent = (event) => {
    // Prevent delayed click events bubbling through closing menus on iOS #1026
    if (bowser.ios && isMouseEvent(event)) return;

    const gestureEvent = { type: event.type };

    const _convertEvent = convertEvent.bind(null, this._domElement);

    if (event.event) gestureEvent.position = _convertEvent(event.event);
    if (event.events) gestureEvent.positions = event.events.map(_convertEvent);
    if (event.preEvents) gestureEvent.preDrags = event.preEvents.map(_convertEvent);
    if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = event.event.deltaY;

    this.onEvent(gestureEvent);
  };
  onEvent(event) {
    const objects = Utils.cloneArray(this.children);

    for (let i = objects.length - 1; i >= 0; i --) {
      const object = objects[i];
      if (object.onEvent && object.onEvent(event, this)) break;
    }
  }
  setCanvas(domElement) {
    if (this._eventDispatcher) this._removeEventListeners();

    this._domElement = domElement;
    if (domElement) {
      this._eventDispatcher = createListener(domElement);
      this._addEventsListeners();
    }

    return this;
  }
}

export class EventObject3D extends THREE.Object3D {
  onEvent(event) {
    const objects = Utils.cloneArray(this.children);

    for (let i = objects.length - 1; i >= 0; i --) {
      const object = objects[i];
      if (object.onEvent && object.onEvent(event, this)) break;
    }
  }
}
