"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _Rate_instances, _Rate_start, _Rate_priorEventTimestamps, _Rate_lastEventTs, _Rate_eventCount, _Rate_vacuum;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rate = void 0;
const BatchClusterOptions_1 = require("./BatchClusterOptions");
// Implementation notes:
// The prior implementation relied on a weighted average of milliseconds between
// events, which didn't behave well when a series of events happend in the same
// millisecond, and didn't correctly recover if events ceased completely (which
// would be expected if this was an error or timeout rate).
// Keeping each event time in an array makes these calculations more precise,
// but suffers from more memory consumption when measuring high rates and using
// a large periodMs.
class Rate {
    /**
     * @param periodMs the length of time to retain event timestamps for computing
     * rate. Events older than this value will be discarded.
     * @param warmupMs return `null` from {@link #msPerEvent} if it's been less
     * than `warmupMs` since construction or {@link #clear}.
     */
    constructor(periodMs = BatchClusterOptions_1.minuteMs, warmupMs = BatchClusterOptions_1.secondMs) {
        _Rate_instances.add(this);
        this.periodMs = periodMs;
        this.warmupMs = warmupMs;
        _Rate_start.set(this, Date.now());
        _Rate_priorEventTimestamps.set(this, []);
        _Rate_lastEventTs.set(this, null);
        _Rate_eventCount.set(this, 0
        /**
         * @param periodMs the length of time to retain event timestamps for computing
         * rate. Events older than this value will be discarded.
         * @param warmupMs return `null` from {@link #msPerEvent} if it's been less
         * than `warmupMs` since construction or {@link #clear}.
         */
        );
    }
    onEvent() {
        var _a;
        __classPrivateFieldSet(this, _Rate_eventCount, (_a = __classPrivateFieldGet(this, _Rate_eventCount, "f"), _a++, _a), "f");
        const now = Date.now();
        __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").push(now);
        __classPrivateFieldSet(this, _Rate_lastEventTs, now, "f");
    }
    get eventCount() {
        return __classPrivateFieldGet(this, _Rate_eventCount, "f");
    }
    get msSinceLastEvent() {
        return __classPrivateFieldGet(this, _Rate_lastEventTs, "f") == null ? null : Date.now() - __classPrivateFieldGet(this, _Rate_lastEventTs, "f");
    }
    get msPerEvent() {
        const msSinceStart = Date.now() - __classPrivateFieldGet(this, _Rate_start, "f");
        if (__classPrivateFieldGet(this, _Rate_lastEventTs, "f") == null || msSinceStart < this.warmupMs)
            return null;
        __classPrivateFieldGet(this, _Rate_instances, "m", _Rate_vacuum).call(this);
        const events = __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").length;
        return events === 0 ? null : Math.min(this.periodMs, msSinceStart) / events;
    }
    get eventsPerMs() {
        const mpe = this.msPerEvent;
        return mpe == null ? 0 : mpe < 1 ? 1 : 1 / mpe;
    }
    get eventsPerSecond() {
        return this.eventsPerMs * BatchClusterOptions_1.secondMs;
    }
    get eventsPerMinute() {
        return this.eventsPerMs * BatchClusterOptions_1.minuteMs;
    }
    clear() {
        __classPrivateFieldSet(this, _Rate_start, Date.now(), "f");
        __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").length = 0;
        __classPrivateFieldSet(this, _Rate_lastEventTs, null, "f");
        __classPrivateFieldSet(this, _Rate_eventCount, 0, "f");
        return this;
    }
}
exports.Rate = Rate;
_Rate_start = new WeakMap(), _Rate_priorEventTimestamps = new WeakMap(), _Rate_lastEventTs = new WeakMap(), _Rate_eventCount = new WeakMap(), _Rate_instances = new WeakSet(), _Rate_vacuum = function _Rate_vacuum() {
    const expired = Date.now() - this.periodMs;
    const firstValidIndex = __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").findIndex((ea) => ea > expired);
    if (firstValidIndex === -1)
        __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").length = 0;
    else if (firstValidIndex > 0) {
        __classPrivateFieldGet(this, _Rate_priorEventTimestamps, "f").splice(0, firstValidIndex);
    }
};
//# sourceMappingURL=Rate.js.map