"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RainwayConnection = void 0;
const Callback_RainwayVoid__RainwayError_1 = require("./callbacks/Callback_RainwayVoid__RainwayError");
const events_1 = require("./events");
const impls_1 = require("./events/impls");
const gc_pin_1 = require("./gc-pin");
const native_1 = require("./native");
const peer_1 = require("./peer");
const rainway_ffi_1 = require("./rainway-ffi");
/**
 * A connection to the Rainway network over which peer connection requests are transmitted.
 */
class RainwayConnection extends events_1.EventEmitter {
    /** @internal */
    constructor(id, externalId) {
        super();
        this.pinned = new gc_pin_1.GCPin(this);
        this.id = id;
        this.externalId = externalId !== null && externalId !== void 0 ? externalId : "";
        this._peers = [];
        (0, native_1.invokeOrError)("rainway_connection_set_connection_request_handler", () => native_1.native.rainway_connection_set_connection_request_handler(id.toString(), new rainway_ffi_1.RainwayConnectionPeerConnectionRequestHandlerDef({
            userData: new rainway_ffi_1.RainwayUserDataDef({
                data: native_1.NULL_POINTER,
                drop: () => {
                    // nothing to do
                },
            }),
            handler: (_, ev) => {
                this.emit("peer-request", new impls_1.PeerRequestEvent(this, ev, (peer) => {
                    this._peers.push(peer);
                    peer.addEventListener("close", () => {
                        this._peers.splice(this._peers.findIndex((p) => p.id == peer.id), 1);
                    });
                }));
                return native_1.VOID;
            },
        })));
    }
    /**
     *  List of peers connected via this Rainway connection.
     */
    get peers() {
        return this._peers;
    }
    /**
     * Connect to another peer on the Rainway Network.
     * @param options - connection options
     * @returns - connection object
     */
    connect(options) {
        return __awaiter(this, void 0, void 0, function* () {
            const cb = new Callback_RainwayVoid__RainwayError_1.Callback_RainwayVoid__RainwayError();
            (0, native_1.invokeOrError)("rainway_connection_connect_to_peer", () => native_1.native.rainway_connection_connect_to_peer(new rainway_ffi_1.RainwayConnectionConnectToPeerOptionsDef({
                callbackState: cb.callbackState,
            })));
            return cb.promise.then(() => {
                const peer = new peer_1.Peer(this, options.id);
                this._peers.push(peer);
                peer.addEventListener("close", () => {
                    this._peers.splice(this._peers.findIndex((p) => p.id == peer.id), 1);
                });
                return peer;
            });
        });
    }
    /**
     * Destroys the Rainway network connection, including all sub resources.
     */
    close() {
        (0, native_1.invokeOrError)("rainway_close_connection", () => native_1.native.rainway_close_connection(this.id.toString()));
        this.emit("close", new impls_1.CloseEvent(new Error()));
        this.pinned.release();
    }
}
exports.RainwayConnection = RainwayConnection;
//# sourceMappingURL=rainway-connection.js.map