"use strict";
//
//  Copyright (c) Microsoft Corporation. All rights reserved.
//
Object.defineProperty(exports, "__esModule", { value: true });
exports.ForwardedPortsCollection = void 0;
const vscode_jsonrpc_1 = require("vscode-jsonrpc");
const forwardedPortEventArgs_1 = require("./forwardedPortEventArgs");
/**
 * Tracks the list of ports that are currently being forwarded between the SSH client and server,
 * along with the set of channel connections for each forwarded port.
 *
 * Ports forwarded in either direction (client->server or server->client) are tracked in separate
 * collections. Typically within a session the forwarding is done only in one direction, though
 * the protocol supports bi-directional forwarding.
 *
 * @see PortForwardingService.RemoteForwardedPorts
 * @see PortForwardingService.LocalForwardedPorts
 */
class ForwardedPortsCollection {
    constructor() {
        /**
         * Maintains a mapping from port keys to port objects and channels for the port.
         *
         * The ForwardedPort string representation is used as the keys.
         */
        this.portChannelMap = new Map();
        this.portAddedEmitter = new vscode_jsonrpc_1.Emitter();
        /** Event raised when a port is added to the collection. */
        this.onPortAdded = this.portAddedEmitter.event;
        this.portUpdatedEmitter = new vscode_jsonrpc_1.Emitter();
        /**
         * Event raised when a port in the collection is updated. "Updating" a port doesn't
         * change anything at the SSH protocol level, but the application may use this event
         * as a signal to update or refresh its state for the forwarded port.
         */
        this.onPortUpdated = this.portUpdatedEmitter.event;
        this.portRemovedEmitter = new vscode_jsonrpc_1.Emitter();
        /** Event raised when a port is removed from the collection. */
        this.onPortRemoved = this.portRemovedEmitter.event;
        this.portChannelAddedEmitter = new vscode_jsonrpc_1.Emitter();
        /** Event raised when a channel is added to the collection. */
        this.onPortChannelAdded = this.portChannelAddedEmitter.event;
        this.portChannelRemovedEmitter = new vscode_jsonrpc_1.Emitter();
        /** Event raised when a channel is removed from the collection. */
        this.onPortChannelRemoved = this.portChannelRemovedEmitter.event;
    }
    /** Gets the number of ports in the collection. */
    get size() {
        return this.portChannelMap.size;
    }
    /** Checks whether a port is in the collection. */
    has(port) {
        return this.portChannelMap.has(port.toString());
    }
    /** Lists all the ports in the collection. */
    *values() {
        for (const [port, channels] of this.portChannelMap.values()) {
            yield port;
        }
    }
    /** Iterates over all the ports in the collection. */
    [Symbol.iterator]() {
        return this.values();
    }
    /** Lists all the ports in the collection. */
    *entries() {
        for (const [port, channels] of this.portChannelMap.values()) {
            yield [port, port];
        }
    }
    /**
     * Lists all the ports in the collection.
     * (In a set, the keys are the same as the values.)
     */
    keys() {
        return this.values();
    }
    /** Iterates over all the ports in the collection, invoking a callback function on each. */
    forEach(callbackfn, thisArg) {
        for (const [port, channels] of this.portChannelMap.values()) {
            callbackfn.apply(thisArg, [port, port, this]);
        }
    }
    getChannels(port) {
        const portAndChannels = this.portChannelMap.get(port.toString());
        if (!portAndChannels) {
            throw new Error(`Port ${port} is not in the collection.`);
        }
        return portAndChannels[1];
    }
    /** Finds the first port in the collection that matches a predicate. */
    find(predicate) {
        for (const port of this.values()) {
            if (predicate(port)) {
                return port;
            }
        }
        return undefined;
    }
    /* @internal */
    addOrUpdatePort(port) {
        if (this.has(port)) {
            this.portUpdatedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port));
        }
        this.portChannelMap.set(port.toString(), [port, []]);
        this.portAddedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port));
    }
    /* @internal */
    removePort(port) {
        if (!this.has(port)) {
            return false;
        }
        this.portChannelMap.delete(port.toString());
        this.portRemovedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port));
        return true;
    }
    /* @internal */
    addChannel(port, channel) {
        const portAndChannels = this.portChannelMap.get(port.toString());
        if (!portAndChannels) {
            throw new Error(`Port ${port} is not in the collection.`);
        }
        const portChannels = portAndChannels[1];
        if (portChannels.find((c) => c.channelId === channel.channelId)) {
            throw new Error(`Channel ${channel.channelId} is already in the collection for port ${port}`);
        }
        portChannels.push(channel);
        channel.onClosed(() => this.tryRemoveChannel(port, channel));
        this.portChannelAddedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortChannelEventArgs(port, channel));
    }
    tryRemoveChannel(port, channel) {
        const portAndChannels = this.portChannelMap.get(port.toString());
        if (portAndChannels) {
            const portChannels = portAndChannels[1];
            const index = portChannels.findIndex((c) => c.channelId === channel.channelId);
            if (index >= 0) {
                portChannels.splice(index, 1);
                this.portChannelRemovedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortChannelEventArgs(port, channel));
            }
        }
    }
    toString() {
        return [...this].join(', ');
    }
}
exports.ForwardedPortsCollection = ForwardedPortsCollection;
//# sourceMappingURL=https://github.com/VSCodium/sourcemaps/releases/download/stable-4c0b0c6cc561d2d3636d1ec250935431876ce4dc/node_modules-@microsoft-dev-tunnels-ssh-tcp-events-forwardedPortsCollection.js.map