import '../../assert/js/assert.js';
import '../../globals.js';
// Copyright 2019-2023, University of Colorado Boulder
/**
 * CallbackTimer is a timer that calls a set of registered callbacks.
 * It utilizes AXON/stepTimer, but provides a higher level of abstraction, hiding the details of managing stepTimer.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
import axon from './axon.js';
import stepTimer from './stepTimer.js';
export default class CallbackTimer {
    constructor(options) {
        this.callbacks = [];
        // initial delay between when start is called and the timer first fires, in ms
        this._delay = 400;
        // fire the timer at this continuous interval, in ms
        this._interval = 100;
        // identifier for timer associated with the initial delay
        this.delayID = null;
        // identifier for timer associated with the continuous interval
        this.intervalID = null;
        // has the timer fired since it was started?
        this.fired = false;
        if (options?.delay !== undefined) {
            this.delay = options.delay;
        }
        if (options?.interval !== undefined) {
            this.interval = options.interval;
        }
        if (options?.callback) {
            this.callbacks.push(options.callback);
        }
    }
    isRunning() {
        return (this.delayID !== null || this.intervalID !== null);
    }
    start() {
        if (!this.isRunning()) {
            this.fired = false;
            this.delayID = stepTimer.setTimeout(() => {
                this.delayID = null;
                this.intervalID = stepTimer.setInterval(() => this.fire(), this.interval);
                // fire after scheduling the intervalID, so that isRunning will be true for callbacks, see sun#216
                this.fire();
            }, this.delay);
        }
    }
    /**
     * Stops the timer.
     * @param fire - should we fire if we haven't fired already?
     */
    stop(fire) {
        if (this.isRunning()) {
            if (this.delayID) {
                stepTimer.clearTimeout(this.delayID);
                this.delayID = null;
            }
            if (this.intervalID) {
                stepTimer.clearInterval(this.intervalID);
                this.intervalID = null;
            }
            if (fire && !this.fired) {
                this.fire();
            }
        }
    }
    addCallback(callback) {
        if (!this.callbacks.includes(callback)) {
            this.callbacks.push(callback);
        }
    }
    removeCallback(callback) {
        const index = this.callbacks.indexOf(callback);
        if (index !== -1) {
            this.callbacks.splice(index, 1);
        }
    }
    /**
     * Calls all callbacks. Clients are free to call this when the timer is not running.
     */
    fire() {
        const callbacksCopy = this.callbacks.slice(0);
        for (let i = 0; i < callbacksCopy.length; i++) {
            callbacksCopy[i]();
        }
        this.fired = true;
    }
    set delay(delay) {
        assert && assert(delay >= 0, `bad value for delay: ${delay}`);
        this._delay = delay;
    }
    get delay() {
        return this._delay;
    }
    set interval(interval) {
        assert && assert(interval > 0, `bad value for interval: ${interval}`);
        this._interval = interval;
    }
    get interval() {
        return this._interval;
    }
    dispose() {
        this.stop(false);
        this.callbacks.length = 0;
    }
}
axon.register('CallbackTimer', CallbackTimer);
//# sourceMappingURL=CallbackTimer.js.map