"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var HaikuGlobal_1 = require("./HaikuGlobal");
var HaikuBase_1 = require("./HaikuBase");
var assign_1 = require("./vendor/assign");
var raf_1 = require("./vendor/raf");
var NUMBER = 'number';
var DEFAULT_OPTIONS = {
    frameDuration: 16.666,
    frameDelay: 16.666,
    marginOfErrorForDelta: 1.0,
};
if (!HaikuGlobal_1.default.HaikuGlobalAnimationHarness) {
    HaikuGlobal_1.default.HaikuGlobalAnimationHarness = {};
    HaikuGlobal_1.default.HaikuGlobalAnimationHarness.queue = [];
    HaikuGlobal_1.default.HaikuGlobalAnimationHarness.frame = function () {
        var queue = HaikuGlobal_1.default.HaikuGlobalAnimationHarness.queue;
        var length = queue.length;
        for (var i = 0; i < length; i++) {
            queue[i]();
        }
        HaikuGlobal_1.default.HaikuGlobalAnimationHarness.raf = raf_1.default.request(HaikuGlobal_1.default.HaikuGlobalAnimationHarness.frame);
    };
    HaikuGlobal_1.default.HaikuGlobalAnimationHarness.cancel = function () {
        if (HaikuGlobal_1.default.HaikuGlobalAnimationHarness.raf) {
            raf_1.default.cancel(HaikuGlobal_1.default.HaikuGlobalAnimationHarness.raf);
        }
    };
    HaikuGlobal_1.default.HaikuGlobalAnimationHarness.frame();
}
var HaikuClock = (function (_super) {
    __extends(HaikuClock, _super);
    function HaikuClock(tickables, component, options) {
        var _this = _super.call(this) || this;
        _this._tickables = tickables;
        _this._component = component;
        _this.assignOptions(options);
        _this._isRunning = false;
        _this.reinitialize();
        HaikuGlobal_1.default.HaikuGlobalAnimationHarness.queue.push(_this.run.bind(_this));
        _this.GLOBAL_ANIMATION_HARNESS = HaikuGlobal_1.default.HaikuGlobalAnimationHarness;
        return _this;
    }
    HaikuClock.prototype.reinitialize = function () {
        this._numLoopsRun = 0;
        this._localFramesElapsed = 0;
        this._localTimeElapsed = 0;
        this._deltaSinceLastTick = 0;
        this._localExplicitlySetTime = null;
        return this;
    };
    HaikuClock.prototype.addTickable = function (tickable) {
        this._tickables.push(tickable);
        return this;
    };
    HaikuClock.prototype.assignOptions = function (options) {
        this.options = assign_1.default(this.options || {}, DEFAULT_OPTIONS, options || {});
        return this;
    };
    HaikuClock.prototype.run = function () {
        if (this.isRunning()) {
            if (this.isTimeControlled()) {
                this.tick();
            }
            else {
                this._numLoopsRun++;
                var prevTime = this._localTimeElapsed;
                var nextTime = prevTime + this.options.frameDuration;
                var deltaSinceLastTick = nextTime - prevTime + this._deltaSinceLastTick;
                if (deltaSinceLastTick >=
                    this.options.frameDelay - this.options.marginOfErrorForDelta) {
                    this.tick();
                    this._localFramesElapsed++;
                    this._localTimeElapsed = nextTime;
                    this._deltaSinceLastTick = 0;
                }
                else {
                    this._deltaSinceLastTick = deltaSinceLastTick;
                }
            }
        }
        return this;
    };
    HaikuClock.prototype.tick = function () {
        for (var i = 0; i < this._tickables.length; i++) {
            this._tickables[i].performTick();
        }
        return this;
    };
    HaikuClock.prototype.getTime = function () {
        return this.getExplicitTime();
    };
    HaikuClock.prototype.setTime = function (time) {
        this._localExplicitlySetTime = parseInt(time || 0, 10);
        return this;
    };
    HaikuClock.prototype.getFPS = function () {
        return Math.round(1000 / this.options.frameDuration);
    };
    HaikuClock.prototype.getExplicitTime = function () {
        if (this.isTimeControlled()) {
            return this.getControlledTime();
        }
        return this.getRunningTime();
    };
    HaikuClock.prototype.getControlledTime = function () {
        return this._localExplicitlySetTime;
    };
    HaikuClock.prototype.isTimeControlled = function () {
        return typeof this._localExplicitlySetTime === NUMBER;
    };
    HaikuClock.prototype.getRunningTime = function () {
        return this._localTimeElapsed;
    };
    HaikuClock.prototype.isRunning = function () {
        return this._isRunning;
    };
    HaikuClock.prototype.start = function () {
        this._isRunning = true;
        return this;
    };
    HaikuClock.prototype.stop = function () {
        this._isRunning = false;
        return this;
    };
    HaikuClock.prototype.getFrameDuration = function () {
        return this.options.frameDuration;
    };
    return HaikuClock;
}(HaikuBase_1.default));
exports.default = HaikuClock;
//# sourceMappingURL=HaikuClock.js.map