"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamRequestEvent = exports.PeerRequestEvent = exports.PeerLeaveEvent = exports.PeerJoinEvent = exports.PeerStateChangeEvent = exports.MessageEvent = exports.LogEvent = exports.InputEvent = exports.CloseEvent = exports.DataChannelEvent = void 0;
const ref_napi_1 = __importDefault(require("ref-napi"));
const ref_array_di_1 = __importDefault(require("ref-array-di"));
const _1 = require(".");
const Callback_RainwayPeerId__RainwayError_1 = require("../callbacks/Callback_RainwayPeerId__RainwayError");
const Callback_RainwayStreamId__RainwayError_1 = require("../callbacks/Callback_RainwayStreamId__RainwayError");
const models_1 = require("../models");
const native_1 = require("../native");
const outbound_stream_1 = require("../outbound-stream");
const peer_1 = require("../peer");
const rainway_ffi_1 = require("../rainway-ffi");
const refArray = (0, ref_array_di_1.default)(ref_napi_1.default);
const NativeUInt32Array = refArray(ref_napi_1.default.types.uint32);
/**
 * An event that occurs when a {@link DataChannel} is created.
 */
class DataChannelEvent extends _1.BaseEvent {
}
exports.DataChannelEvent = DataChannelEvent;
/**
 * An event that occurs when something is closed.
 */
class CloseEvent extends _1.BaseEvent {
}
exports.CloseEvent = CloseEvent;
/**
 * An event that occurs when input arrives for a given {@link OutboundStream}.
 * Can be used to prevent input event processing, preventing the host from handling the input.
 */
class InputEvent extends _1.BaseEvent {
    /* @internal */
    constructor(native) {
        super(new models_1.InputBody(native.input, native.heldKeys, Number(native.numHeldKeys).valueOf()));
        this._isPrevented = false;
        this.id = BigInt(native.peer);
    }
    /**
     * Flag indicating if the input event has been prevented, in which case it will be ignored by the host.
     */
    get defaultPrevented() {
        return this._isPrevented;
    }
    /**
     * Prevents the input event from being processed by the host.
     */
    preventDefault() {
        this._isPrevented = true;
    }
}
exports.InputEvent = InputEvent;
/**
 * An event that occurs when the {@link RainwaySDK} logs data.
 */
class LogEvent extends _1.BaseEvent {
}
exports.LogEvent = LogEvent;
/**
 * An event that occurs when a {@link DataChannel} gets a message.
 */
class MessageEvent extends _1.BaseEvent {
    /**
     * UTF8 representation of the message data.
     */
    get asString() {
        return Buffer.from(this.data).toString("utf-8");
    }
}
exports.MessageEvent = MessageEvent;
/**
 * An event that occurs when a {@link Peer} changes {@link RainwayPeerState}.
 */
class PeerStateChangeEvent extends _1.BaseEvent {
}
exports.PeerStateChangeEvent = PeerStateChangeEvent;
/**
 *  An event that occurs when a {@link Peer} joins a {@link OutboundStream}.
 */
class PeerJoinEvent extends _1.BaseEvent {
}
exports.PeerJoinEvent = PeerJoinEvent;
/**
 * An event that occurs when a {@link Peer} leaves a {@link OutboundStream}.
 */
class PeerLeaveEvent extends _1.BaseEvent {
}
exports.PeerLeaveEvent = PeerLeaveEvent;
/**
 * An event that occurs when a remote peer requests to connect.
 */
class PeerRequestEvent extends _1.BaseRequestEvent {
    /* @internal */
    constructor(owner, input, onAccepted, onRejected) {
        var _a;
        super(onAccepted, onRejected);
        this.owner = owner;
        this.input = input;
        this.id = BigInt(input.id);
        this.externalId = (_a = input.externalId) !== null && _a !== void 0 ? _a : "";
    }
    acceptInternal(options) {
        var _a, _b;
        const cb = new Callback_RainwayPeerId__RainwayError_1.Callback_RainwayPeerId__RainwayError();
        const opts = new rainway_ffi_1.RainwayPeerOptionsDef({
            portMin: (_a = options === null || options === void 0 ? void 0 : options.minPort) !== null && _a !== void 0 ? _a : 0,
            portMax: (_b = options === null || options === void 0 ? void 0 : options.maxPort) !== null && _b !== void 0 ? _b : 0,
        });
        (0, native_1.invokeOrError)("rainway_connection_accept_request", () => native_1.native.rainway_connection_accept_request(this.owner.id.toString(), this.input.id, opts, cb.callbackState));
        return cb.promise.then((id) => new peer_1.Peer(this.owner, id));
    }
    rejectInternal(reason) {
        (0, native_1.invokeOrError)("rainway_connection_reject_request", () => native_1.native.rainway_connection_reject_request(this.owner.id.toString(), this.input.id, reason !== null && reason !== void 0 ? reason : null));
        return Promise.resolve();
    }
}
exports.PeerRequestEvent = PeerRequestEvent;
/**
 * An event that occurs when a remote peer requests an {@link OutboundStream}.
 */
class StreamRequestEvent extends _1.BaseRequestEvent {
    /** @internal */
    constructor(owner, input, onAccepted, onRejected) {
        super(onAccepted, onRejected);
        this.owner = owner;
        this.input = input;
        this.id = owner.id;
        this.externalId = owner.externalId;
        this.permissions = input.inputLevel;
        this.supportsAppIsolation = input.supportsAppIsolation;
    }
    acceptInternal(options) {
        var _a, _b, _c, _d, _e, _f;
        const cb = new Callback_RainwayStreamId__RainwayError_1.Callback_RainwayStreamId__RainwayError();
        // protect the user from doing specifying processIds for a non-app isolated stream
        if ((options === null || options === void 0 ? void 0 : options.processIds) &&
            (options === null || options === void 0 ? void 0 : options.processIds.length) > 0 &&
            (options === null || options === void 0 ? void 0 : options.type) !== rainway_ffi_1.RainwayStreamType.AppIsolation) {
            throw new Error(`OutboundStreamOptions.type must be AppIsolation. Either change type or remote the processIds (length: ${(_a = options.processIds.length) !== null && _a !== void 0 ? _a : 0})`);
        }
        // and from trying to do app isolation for a peer that doesn't support it
        if ((options === null || options === void 0 ? void 0 : options.type) == rainway_ffi_1.RainwayStreamType.AppIsolation &&
            !this.input.supportsAppIsolation) {
            throw new Error("OutboundStreamOptions.type cannot be AppIsolation as the remote peer does not support app isolation");
        }
        const data = new NativeUInt32Array((_b = options === null || options === void 0 ? void 0 : options.processIds) !== null && _b !== void 0 ? _b : []);
        const opts = new rainway_ffi_1.RainwayStreamStartOptionsDef({
            type: (_c = options === null || options === void 0 ? void 0 : options.type) !== null && _c !== void 0 ? _c : rainway_ffi_1.RainwayStreamType.FullDesktop,
            defaultPermissions: (_d = options === null || options === void 0 ? void 0 : options.permissions) !== null && _d !== void 0 ? _d : rainway_ffi_1.RainwayInputLevel.None,
            processIds: data.buffer,
            processIdsLen: (_f = (_e = options === null || options === void 0 ? void 0 : options.processIds) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0,
            callbackState: cb.callbackState,
        });
        (0, native_1.invokeOrError)("rainway_peer_connection_accept_stream_request", () => native_1.native.rainway_peer_connection_accept_stream_request(this.owner.connection.id.toString(), this.owner.id.toString(), opts));
        return cb.promise.then((id) => {
            var _a, _b;
            return new outbound_stream_1.OutboundStream(this.owner, id, (_a = options === null || options === void 0 ? void 0 : options.type) !== null && _a !== void 0 ? _a : rainway_ffi_1.RainwayStreamType.FullDesktop, (_b = options === null || options === void 0 ? void 0 : options.processIds) !== null && _b !== void 0 ? _b : []);
        });
    }
    rejectInternal(reason) {
        (0, native_1.invokeOrError)("rainway_peer_connection_reject_stream_request", () => native_1.native.rainway_peer_connection_reject_stream_request(this.owner.connection.id.toString(), this.owner.id.toString(), reason !== null && reason !== void 0 ? reason : null));
        return Promise.resolve();
    }
}
exports.StreamRequestEvent = StreamRequestEvent;
//# sourceMappingURL=impls.js.map