"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.HotWebSocketClient = void 0;
const socket_io_client_1 = require("socket.io-client");
const uuid_1 = require("uuid");
/**
 * The client-side websocket client that can be used to connect to the server.
 */
class HotWebSocketClient {
    constructor(url, socket = null) {
        this.url = url;
        this.socket = socket;
        this.persistentData = {};
        this.authorizedValue = null;
        this.onConnectError = null;
        this.onError = null;
        this.onDisconnect = null;
    }
    /**
     * Use an already connected socket.
     */
    useSocket(socket) {
        this.socket = socket;
    }
    /**
     * Connect to the websocket server.
     */
    connect() {
        return __awaiter(this, arguments, void 0, function* (auth = null, query = null, options = undefined) {
            let socketObj = options;
            if (auth != null) {
                if (socketObj == null)
                    socketObj = {};
                socketObj = Object.assign(Object.assign({}, socketObj), { auth: auth });
            }
            if (query != null) {
                if (socketObj == null)
                    socketObj = {};
                socketObj = Object.assign(Object.assign({}, socketObj), { query: query });
            }
            this.socket = (0, socket_io_client_1.io)(this.url, socketObj);
            return (new Promise((resolve, reject) => {
                this.socket.on("connect", () => {
                    if (this.onConnect != null)
                        this.onConnect();
                    resolve();
                });
                this.socket.on("connect_error", (err) => {
                    if (this.onConnectError != null) {
                        this.onConnectError(err);
                        return;
                    }
                    reject(err);
                });
                this.socket.on("error", (err) => {
                    if (this.onError != null) {
                        this.onError(err);
                        return;
                    }
                    reject(err);
                });
                this.socket.on("disconnect", () => {
                    if (this.onDisconnect != null)
                        this.onDisconnect();
                });
            }));
        });
    }
    /**
     * Listen for a client event.
     */
    on(event, callback, uuid = null) {
        this.socket.on(event, function (uuid2, data) {
            if (data.uuid != null) {
                if (uuid2 != null) {
                    if (data.uuid === uuid2)
                        callback(data.data, data.uuid);
                }
                else
                    callback(data.data, data.uuid);
            }
            else
                callback(data, uuid2);
        }.bind(this, uuid));
    }
    /**
     * Listen for a client event without any intervention. The event will not have any
     * interaction with the event uuid.
     */
    onRaw(event, callback) {
        this.socket.on(event, callback);
    }
    /**
     * Stop listening for a client event.
     */
    off(event) {
        this.socket.off(event, null);
    }
    /**
     * Listen for a client event once.
     */
    once(event, callback, uuid = null) {
        this.socket.once(event, function (uuid2, data) {
            if (data.uuid != null) {
                if (uuid2 != null) {
                    if (data.uuid === uuid2)
                        callback(data.data, data.uuid);
                }
                else
                    callback(data.data, data.uuid);
            }
            else
                callback(data, uuid2);
        }.bind(this, uuid));
    }
    /**
     * Listen for a client event once without any intervention.
     */
    onceRaw(event, callback) {
        this.socket.once(event, callback);
    }
    /**
     * Get the socket's id.
     */
    getId() {
        return (this.socket.id);
    }
    /**
     * Is the socket connected?
     */
    isConnected() {
        if (this.socket == null)
            return (false);
        if (this.socket.connected === false)
            return (false);
        return (true);
    }
    /**
     * Send an event to the client. You can optionally receive a response from the client.
     *
     * @returns The uuid of the event sent.
     */
    send(event, data, uuid = null) {
        if (this.socket == null)
            throw new Error(`Client socket is null. Unable to send event ${event}`);
        if (this.socket.connected === false)
            throw new Error(`Client socket is not connected. Unable to send event ${event}`);
        if (uuid == null)
            uuid = (0, uuid_1.v4)();
        this.socket.emit(event, { uuid: uuid, data: data });
        return (uuid);
    }
    /**
     * Send an event to the client, and wait for a response. Every time
     * data is received from this event, the callback will be called.
     */
    sendOn(event_1, data_1, callback_1) {
        return __awaiter(this, arguments, void 0, function* (event, data, callback, uuid = null) {
            let result = yield new Promise((resolve, reject) => {
                if (uuid == null)
                    uuid = (0, uuid_1.v4)();
                this.on(event, function (uuid2, data) {
                    callback(data, uuid2);
                    resolve(data);
                }.bind(this, uuid), uuid);
                this.send(event, data, uuid);
            });
            return (result);
        });
    }
    /**
     * Send an event to the client, and wait for a response once.
     */
    sendOnce(event_1, data_1) {
        return __awaiter(this, arguments, void 0, function* (event, data, uuid = null) {
            let result = yield new Promise((resolve, reject) => {
                if (uuid == null)
                    uuid = (0, uuid_1.v4)();
                this.once(event, function (uuid2, data) {
                    resolve(data);
                }.bind(this, uuid), uuid);
                this.send(event, data, uuid);
            });
            return (result);
        });
    }
    /**
     * Disconnect the client.
     */
    disconnect(removeFromServer = true) {
        if (this.socket == null)
            return;
        if (this.socket.connected === false)
            return;
        this.socket.disconnect();
    }
}
exports.HotWebSocketClient = HotWebSocketClient;
//# sourceMappingURL=HotWebSocketClient.js.map