/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
import { assert, BeEvent, BentleyStatus } from "@itwin/core-bentley";
import { IModelError } from "../../IModelError";
/** Defines a transport for push messages.
 *  @internal
 */
export class RpcPushTransport {
    onMessage;
}
/** Defines a source of push messages.
 *  @internal
 */
export class RpcPushService {
    /** The push service for the dedicated backend (for example, an electron or mobile app). */
    static dedicated = new RpcPushService("dedicated");
    name;
    constructor(name) {
        this.name = name;
    }
}
/** Defines a named stream of push messages.
 *  @internal
 */
export class RpcPushChannel {
    /** @internal */
    static enabled = false;
    static _channels = new Map();
    static setup(transport) {
        transport.onMessage = RpcPushChannel.notifySubscribers.bind(RpcPushChannel);
        RpcPushChannel.enabled = true;
    }
    static notifySubscribers(channelId, messageData) {
        const channel = this._channels.get(channelId);
        if (!channel)
            return;
        for (const subscriber of channel._subscribers)
            subscriber.onMessage.raiseEvent(messageData);
    }
    _subscribers = [];
    name;
    service;
    get id() { return RpcPushChannel.formatId(this.name, this.service); }
    get enabled() { return RpcPushChannel.enabled; }
    subscribe() {
        const subscription = new RpcPushSubscription(this);
        this._subscribers.push(subscription);
        return subscription;
    }
    static formatId(name, service) {
        return `${service.name}-${name}`;
    }
    constructor(name, service) {
        this.name = name;
        this.service = service;
    }
    /** Creates a new RpcPushChannel.
     * @throws IModelError if a channel with the specified name and service already exist.
     */
    static create(name, service = RpcPushService.dedicated) {
        return this.get(name, service, false);
    }
    /** Obtains an RpcPushChannel, creating it if one with the specified name and service does not already exists. */
    static obtain(name, service = RpcPushService.dedicated) {
        return this.get(name, service, true);
    }
    static get(name, service, reuseExisting) {
        const id = this.formatId(name, service);
        let channel = this._channels.get(id);
        if (channel) {
            if (!reuseExisting)
                throw new IModelError(BentleyStatus.ERROR, `Channel "${id}" already exists.`);
            ++channel._refCount;
            return channel;
        }
        channel = new RpcPushChannel(name, service);
        this._channels.set(id, channel);
        return channel;
    }
    _refCount = 1;
    dispose() {
        if (this.isDisposed)
            return;
        assert(this._refCount > 0);
        if (--this._refCount === 0) {
            RpcPushChannel._channels.delete(this.id);
            this._subscribers.length = 0;
        }
    }
    get isDisposed() {
        return 0 === this._refCount;
    }
}
/** Receives push messages from the backend.
 *  @internal
 */
export class RpcPushSubscription {
    channel;
    onMessage = new BeEvent();
    /** @internal */
    constructor(channel) {
        this.channel = channel;
    }
}
/** Sends push messages to the frontend.
 *  @internal
 */
export class RpcPushConnection {
    static for(_channel, _client = undefined) {
        throw new IModelError(BentleyStatus.ERROR, "Not implemented.");
    }
    channel;
    client;
    constructor(channel, client) {
        this.channel = channel;
        this.client = client;
    }
}
//# sourceMappingURL=RpcPush.js.map