"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.RpcPendingQueue = void 0;
const RpcConstants_1 = require("./RpcConstants");
const RpcRequest_1 = require("./RpcRequest");
/* eslint-disable @typescript-eslint/no-deprecated */
/** Manages pending RPC requests and responses.
 * @internal
 */
class RpcPendingQueue {
    static instance;
    static initialize() {
        if (!RpcPendingQueue.instance) {
            RpcPendingQueue.instance = new RpcPendingQueue();
        }
    }
    _pendingInterval = undefined;
    _pending = [];
    _pendingLock = 0;
    constructor() {
        // eslint-disable-next-line @typescript-eslint/unbound-method
        RpcRequest_1.RpcRequest.events.addListener(this.requestEventHandler, this);
    }
    requestEventHandler(type, request) {
        if (type !== RpcConstants_1.RpcRequestEvent.StatusChanged)
            return;
        switch (request.status) {
            case RpcConstants_1.RpcRequestStatus.Submitted: {
                this.enqueuePending(request);
                break;
            }
            case RpcConstants_1.RpcRequestStatus.Resolved:
            case RpcConstants_1.RpcRequestStatus.Rejected:
            case RpcConstants_1.RpcRequestStatus.NotFound:
            case RpcConstants_1.RpcRequestStatus.Cancelled: {
                this.dequeuePending(request);
                break;
            }
        }
    }
    enqueuePending(request) {
        this._pending.push(request);
        this.setPendingInterval();
    }
    dequeuePending(request) {
        if (this._pendingLock)
            return;
        const i = this._pending.indexOf(request);
        this._pending.splice(i, 1);
        this.clearPendingInterval();
    }
    _pendingIntervalHandler = function () {
        const now = new Date().getTime();
        ++this._pendingLock;
        for (const request of this._pending) {
            const retry = request.retryAfter ?? request.retryInterval;
            if (request.connecting || (request.lastSubmitted + retry) > now) {
                continue;
            }
            request.submit(); // eslint-disable-line @typescript-eslint/no-floating-promises
        }
        --this._pendingLock;
        this.cleanupPendingQueue();
    }.bind(this);
    cleanupPendingQueue() {
        if (this._pendingLock)
            return;
        let i = this._pending.length;
        while (i--) {
            if (!this._pending[i].pending && !RpcConstants_1.RpcRequestStatus.isTransientError(this._pending[i].status)) {
                this._pending.splice(i, 1);
            }
        }
        this.clearPendingInterval();
    }
    setPendingInterval() {
        if (this._pendingInterval)
            return;
        this._pendingInterval = setInterval(this._pendingIntervalHandler, 0);
    }
    clearPendingInterval() {
        if (!this._pending.length) {
            clearInterval(this._pendingInterval);
            this._pendingInterval = undefined;
        }
    }
}
exports.RpcPendingQueue = RpcPendingQueue;
//# sourceMappingURL=RpcPendingQueue.js.map