var dataUtil = require("../core/utils/data_structure_util");

var classUtil = require("../core/utils/class_util");

var _event_util = require("../core/utils/event_util");

var Dispatcher = _event_util.Dispatcher;

var requestAnimationFrame = require("./utils/request_animation_frame");

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

/**
 * @singleton
 * @class qrenderer.animation.GlobalAnimationMgr
 * 
 * Animation manager, global singleton, controls all the animation process.
 * Each QRenderer instance has a GlobalAnimationMgr instance. GlobalAnimationMgr 
 * is designed to manage all the AnimationProcesses inside a qrenderer instance.
 * 
 * 动画管理器，全局单例，控制和调度所有动画过程。每个 qrenderer 实例中会持有一个 
 * GlobalAnimationMgr 实例。GlobalAnimationMgr 会管理 qrenderer 实例中的所有
 * AnimationProcess。
 * 
 * @author pissang(https://github.com/pissang)
 * @docauthor 大漠穷秋 <damoqiongqiu@126.com>
 */
// TODO Additive animation
// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
// https://developer.apple.com/videos/wwdc2014/#236
var GlobalAnimationMgr =
/*#__PURE__*/
function () {
  /**
   * @method constructor GlobalAnimationMgr
   * @param {Object} [options]
   */
  function GlobalAnimationMgr(options) {
    _classCallCheck(this, GlobalAnimationMgr);

    options = options || {};
    this._animationProcessList = [];
    this._running = false;
    this._timestamp;
    this._pausedTime; //ms

    this._pauseStart;
    this._paused = false;
    Dispatcher.call(this);
  }
  /**
   * @method addAnimationProcess
   * 添加 animationProcess
   * @param {qrenderer.animation.GlobalAnimationMgr} animationProcess
   */


  _createClass(GlobalAnimationMgr, [{
    key: "addAnimationProcess",
    value: function addAnimationProcess(animationProcess) {
      this._animationProcessList.push(animationProcess);
    }
    /**
     * @method removeAnimationProcess
     * 删除动画片段
     * @param {qrenderer.animation.GlobalAnimationMgr} animationProcess
     */

  }, {
    key: "removeAnimationProcess",
    value: function removeAnimationProcess(animationProcess) {
      var index = this._animationProcessList.findIndex(animationProcess);

      if (index >= 0) {
        this._animationProcessList.splice(index, 1);
      }
    }
    /**
     * @private
     * @method _update
     */

  }, {
    key: "_update",
    value: function _update() {
      var time = new Date().getTime() - this._pausedTime;

      var delta = time - this._timestamp;

      this._animationProcessList.forEach(function (ap, index) {
        ap.nextFrame(time, delta);
      });

      this._timestamp = time; // TODO:What's going on here?
      // 'frame' should be triggered before stage, because upper application
      // depends on the sequence (e.g., echarts-stream and finish
      // event judge)

      this.trigger('frame', delta);
    }
    /**
     * @private
     * @method _startLoop
     * 这里开始利用requestAnimationFrame递归执行，如果这里的 _update() 不能在16ms的
     * 时间内完成一轮动画，就会出现明显的卡顿。
     * 按照 W3C 的推荐标准 60fps，这里的 step 函数大约每隔 16ms 被调用一次
     * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
     */

  }, {
    key: "_startLoop",
    value: function _startLoop() {
      var self = this;
      this._running = true;

      function nextFrame() {
        if (self._running) {
          requestAnimationFrame(nextFrame);
          !self._paused && self._update();
        }
      }

      requestAnimationFrame(nextFrame);
    }
    /**
     * @method start
     * Start all the animations.
     */

  }, {
    key: "start",
    value: function start() {
      this._timestamp = new Date().getTime();
      this._pausedTime = 0;

      this._startLoop();
    }
    /**
     * @method stop
     * Stop all the animations.
     */

  }, {
    key: "stop",
    value: function stop() {
      this._running = false;
    }
    /**
     * @method pause
     * Pause all the animations.
     */

  }, {
    key: "pause",
    value: function pause() {
      if (!this._paused) {
        this._pauseStart = new Date().getTime();
        this._paused = true;
      }
    }
    /**
     * @method resume
     * Resume all the animations.
     */

  }, {
    key: "resume",
    value: function resume() {
      if (this._paused) {
        this._pausedTime += new Date().getTime() - this._pauseStart;
        this._paused = false;
      }
    }
    /**
     * @method clear
     * Clear all the animations.
     */

  }, {
    key: "clear",
    value: function clear() {
      this._animationProcessList.length = 0;
    }
    /**
     * @method isFinished
     * Whether all the animations have finished.
     */

  }, {
    key: "isFinished",
    value: function isFinished() {
      var finished = true;

      this._animationProcessList.forEach(function (animationProcess, index) {
        if (!animationProcess.isFinished()) {
          finished = false;
        }
      });

      return finished;
    }
  }]);

  return GlobalAnimationMgr;
}();

classUtil.mixin(GlobalAnimationMgr, Dispatcher);
var _default = GlobalAnimationMgr;
module.exports = _default;