'use strict';
import find from 'lodash/find';
const FPS = 60;
const FRAME_DURATION = 1000 / FPS;

export default class Game {
  constructor() {
    this._scenes = [];
    this._scene = null;
    this._previousTime = null;
    this._delta = null;
    this._canvas = null;
    this._context = null;
    this._paused = true;
  }
  get canvas() {
    return this._canvas;
  }
  set canvas(canvas) {
    this._canvas = canvas;
    this._context = this._canvas.getContext('2d');
  }
  get scene() {
    return this._scene;
  }
  set scene(name) {
    console.log('Setting scene to ' + name);
    let scene = find(this._scenes, scene => scene.name === name);
    if (scene) {
      this._scene = scene;
    } else {
      throw new Error('Scene ' + name + ' not found');
    }
  }
  addScene(scene) {
    console.log('Added scene ' + scene.name + ' ...');
    this._scenes.push(scene);
  }
  run() {
    this._setup();
    console.log('Running ...');
    this._loop();
  }
  _setup() {
    console.log('Setup ...');
    _setupRequestAnimationFrame();
  }
  _loop() {

    //Call the next iteration of the game loop
    window.requestAnimationFrame(() => { this._loop(); });

    //calculate the delta time between this current timestamp (frame)
    //and the previous
    var now = window.performance.now();
    this._delta = now - this._previousTime;

    //correct any huge unexpected gaps in the delta
    if (this._delta > 1000) {
      this._delta = FRAME_DURATION;
    }

    // Store the current transformation matrix
    this._context.save();

    // Use the identity matrix while clearing the canvas
    this._context.setTransform(1, 0, 0, 1, 0, 0);
    this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);

    // Restore the transform
    this._context.restore();

    //Update all of the game components
    this._scene.update({
      canvas: this._canvas,
      context: this._context,
      delta: this._delta,
      game: this
    });

    //set the current time to be used as the previous
    //for the next frame
    this._previousTime = now;

  }

}

/**
 * This will setup the window.requestAnimationFrame in case it is not defined
 */
function _setupRequestAnimationFrame() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
  }
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = (callback, element) => {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(() => {
        callback(currTime + timeToCall);
      }, timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }
  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = id => {
      clearTimeout(id);
    };
  }
}
