"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 Tiles
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.TileRequestChannels = void 0;
const IpcApp_1 = require("../IpcApp");
const internal_1 = require("./internal");
/** For an [[IpcApp]], allows backend element graphics requests in progress to be canceled. */
class ElementGraphicsChannel extends internal_1.TileRequestChannel {
    constructor() {
        super(...arguments);
        this._canceled = new Map();
    }
    onActiveRequestCanceled(request) {
        const imodel = request.tile.tree.iModel;
        let ids = this._canceled.get(imodel);
        if (!ids)
            this._canceled.set(imodel, ids = []);
        ids.push(request.tile.contentId);
    }
    processCancellations() {
        for (const [imodel, requestIds] of this._canceled) {
            // eslint-disable-next-line @typescript-eslint/no-floating-promises
            IpcApp_1.IpcApp.appFunctionIpc.cancelElementGraphicsRequests(imodel.key, requestIds);
            this._statistics.totalAbortedRequests += requestIds.length;
        }
        this._canceled.clear();
    }
    onIModelClosed(imodel) {
        this._canceled.delete(imodel);
    }
}
/** A set of named [[TileRequestChannel]]s via which content for [[Tile]]s can be requested.
 * @see [[TileAdmin.channels]] for the channels configured for use with the iTwin.js display system.
 * @see [[TileRequestChannels.getForHttp]] for the most typical way of obtaining or registering a channel.
 * @public
 * @extensions
 */
class TileRequestChannels {
    /** `rpcConcurrency` is defined if [[IpcApp.isValid]]; otherwise RPC requests are made over HTTP and use the same limits.
     * @internal
     */
    constructor(rpcConcurrency, cacheMetadata) {
        /** The maximum number of active requests for a channel that uses HTTP to request content. */
        this.httpConcurrency = 6;
        this._channels = new Map();
        this._rpcConcurrency = rpcConcurrency ?? this.httpConcurrency;
        const elementGraphicsChannelName = "itwinjs-elem-rpc";
        if (undefined !== rpcConcurrency)
            this.elementGraphicsRpc = new ElementGraphicsChannel(elementGraphicsChannelName, rpcConcurrency);
        else
            this.elementGraphicsRpc = new internal_1.TileRequestChannel(elementGraphicsChannelName, this.rpcConcurrency);
        this.add(this.elementGraphicsRpc);
        this.iModelChannels = new internal_1.IModelTileRequestChannels({
            concurrency: this.rpcConcurrency,
            usesHttp: undefined === rpcConcurrency,
            cacheMetadata,
            cacheConcurrency: this.httpConcurrency,
        });
        for (const channel of this.iModelChannels)
            this.add(channel);
    }
    /** The number of registered channels. */
    get size() {
        return this._channels.size;
    }
    /** Look up a registered channel by its name. */
    get(name) {
        return this._channels.get(name);
    }
    /** Return whether the specified channel has been registered. Primarily for debugging. */
    has(channel) {
        const existing = this.get(channel.name);
        return existing !== undefined && existing === channel;
    }
    /** Add a new channel.
     * @throws Error if a channel by the same name has already been registered.
     */
    add(channel) {
        if (this.get(channel.name))
            throw new Error(`Tile request channel ${channel.name} is already registered.`);
        this._channels.set(channel.name, channel);
    }
    /** Extract the host name from a URL for use as the name of the corresponding [[TileRequestChannel]].
     * @throws TypeError if `url` is a string and does not represent a valid URL.
     * @see [[getForHttp]] to obtain or register a channel for the host name.
     */
    static getNameFromUrl(url) {
        if (typeof url === "string")
            url = new URL(url);
        return url.hostname;
    }
    /** Obtain a channel that requests content over HTTP using HTTP 1.1 limits on simultaneous connections.
     * If a channel with the specified name does not already exist, it will be created and registered.
     * @see [[getNameFromUrl]] to obtain a channel name corresponding to a hostname.
     */
    getForHttp(name) {
        let channel = this.get(name);
        if (!channel)
            this.add(channel = new internal_1.TileRequestChannel(name, this.httpConcurrency));
        return channel;
    }
    /** Iterator over all of the channels. */
    [Symbol.iterator]() {
        return this._channels.values()[Symbol.iterator]();
    }
    /** The maximum number of active requests for a channel that uses an RpcInterface to satisfy its requests.
     * For web-based applications, this is the same as [[httpConcurrency]], but for [[IpcApp]]s it is determined by the number of workers threads allocated by the backend.
     */
    get rpcConcurrency() {
        return this._rpcConcurrency;
    }
    /** @internal */
    getIModelTileChannel(tile) {
        return this.iModelChannels.getChannelForTile(tile);
    }
    /** Chiefly for debugging.
     * @internal
     */
    setRpcConcurrency(concurrency) {
        this._rpcConcurrency = concurrency;
        this.iModelChannels.setRpcConcurrency(concurrency);
        this.elementGraphicsRpc.concurrency = concurrency;
    }
    /** Statistics intended primarily for debugging. */
    get statistics() {
        const stats = new internal_1.TileRequestChannelStatistics();
        for (const channel of this)
            channel.statistics.addTo(stats);
        return stats;
    }
    /** Reset all [[statistics]] to zero. */
    resetStatistics() {
        for (const channel of this)
            channel.resetStatistics();
    }
    /** Invoked by [[TileAdmin.processQueue]] when it is about to start enqueuing new requests.
     * @internal
     */
    swapPending() {
        for (const channel of this)
            channel.swapPending();
    }
    /** Invoked by [[TileAdmin.processQueue]] when it is about to start enqueuing new requests.
     * @internal
     */
    process() {
        for (const channel of this)
            channel.process();
    }
    /** Invoked by [[TileAdmin.onIModelClosed]].
     * @internal
     */
    onIModelClosed(iModel) {
        for (const channel of this)
            channel.onIModelClosed(iModel);
    }
    /** Invoked by [[TileAdmin.onShutDown]].
     * @internal
     */
    onShutDown() {
        for (const channel of this)
            channel.cancelAndClearAll();
        this._channels.clear();
    }
}
exports.TileRequestChannels = TileRequestChannels;
//# sourceMappingURL=TileRequestChannels.js.map