/**
 * @module helpers/x/renderer2d
 */
import CamerasOrthographic from '../../cameras/cameras.orthographic';
import ControlsOrthographic from '../../controls/controls.trackballortho';

import {Vector3, Scene, WebGLRenderer} from 'three'

export default class {
  constructor(containerId = 'r2d', orientation = 'default') {
    this._container = null;
    this._renderer = null;
    this._camera = null;
    this._controls = null;
    this._orientation = orientation;
    this._scene = null;
    this._object = null;

    this._initRenderer(containerId);
    this._initCamera();
    this._initScene();
    this._initControls();

    // setup event listeners
    this._onScroll = this._onScroll.bind(this);
    this._onWindowResize = this._onWindowResize.bind(this);
    this.addEventListeners();
  }

  add(object) {
    this._object = object;
    this._scene.add(this._object);

    this._setupCamera(this._object.stack);
    this._orientCamera(this._object, this._orientation);

    this._object.canvasWidth = this._container.clientWidth;
    this._object.canvasHeight = this._container.clientHeight;
  }

  addEventListeners() {
    this._controls.addEventListener('OnScroll', this._onScroll, false);
    addEventListener('resize', this._onWindowResize, false);
  }

  removeEventListeners() {
    this._controls.removeEventListener('OnScroll', this._onScroll, false);
    removeEventListener('resize', this._onWindowResize, false);
  }

  animate() {
    this._controls.update();
    this._renderer.render(this._scene, this._camera);

    // request new frame
    requestAnimationFrame(this.animate.bind(this));
  }

  // private methods

  _initRenderer(containerId) {
    // renderer
    this._container = document.getElementById(containerId);
    this._renderer = new WebGLRenderer({
      antialias: true,
    });
    this._renderer.setSize(this._container.clientWidth, this._container.clientHeight);
    this._renderer.setClearColor(0x212121, 1);
    this._renderer.setPixelRatio(devicePixelRatio);
    this._container.appendChild(this._renderer.domElement);
  }

  _initCamera() {
    this._camera = new CamerasOrthographic(
      this._container.clientWidth / -2,
      this._container.clientWidth / 2,
      this._container.clientHeight / 2,
      this._container.clientHeight / -2,
      1,
      1000
    );
  }

  _initScene() {
    this._scene = new Scene();
  }

  _initControls() {
    // controls
    this._controls = new ControlsOrthographic(this._camera, this._container);
    this._controls.staticMoving = true;
    this._controls.noRotate = true;
    this._camera.controls = this._controls;
  }

  _setupCamera(stack) {
    // set camera
    let worldbb = stack.worldBoundingBox();
    let lpsDims = new Vector3(
      worldbb[1] - worldbb[0],
      worldbb[3] - worldbb[2],
      worldbb[5] - worldbb[4]
    );

    // box: {halfDimensions, center}
    let box = {
      center: stack.worldCenter().clone(),
      halfDimensions: new Vector3(lpsDims.x + 10, lpsDims.y + 10, lpsDims.z + 10),
    };

    // init and zoom
    let canvas = {
      width: this._container.clientWidth,
      height: this._container.clientHeight,
    };

    this._camera.directions = [stack.xCosine, stack.yCosine, stack.zCosine];
    this._camera.box = box;
    this._camera.canvas = canvas;
    this._camera.update();
    this._camera.fitBox(2);
  }

  _orientCamera(target, orientation = 'default') {
    this._camera.orientation = orientation;
    this._camera.update();
    this._camera.fitBox(2);
    target.orientation = this._camera.stackOrientation;
  }

  _onWindowResize() {
    this._camera.canvas = {
      width: this._container.clientWidth,
      height: this._container.clientHeight,
    };
    this._camera.fitBox(2);
    this._renderer.setSize(this._container.clientWidth, this._container.clientHeight);
    this._object.canvasWidth = this._container.clientWidth;
    this._object.canvasHeight = this._container.clientHeight;
  }

  _onScroll(event) {
    if (event.delta > 0) {
      if (this._object.index >= this._object.orientationMaxIndex) {
        return false;
      }
      this._object.index += 1;
    } else {
      if (this._object.index <= 0) {
        return false;
      }
      this._object.index -= 1;
    }
  }
}
