"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("@deepstream/types");
const constants_1 = require("../../constants");
const constants_2 = require("../websocket/text/text-protocol/constants");
const message_parser_1 = require("./message-parser");
/**
 * This class wraps around a websocket
 * and provides higher level methods that are integrated
 * with deepstream's message structure
 */
class MQTTSocketWrapper {
    constructor(socket, handshakeData, services, logger) {
        this.socket = socket;
        this.handshakeData = handshakeData;
        this.services = services;
        this.logger = logger;
        this.socketType = 'mqtt';
        this.userId = null;
        this.serverData = null;
        this.clientData = null;
        this.isRemote = false;
        this.isClosed = false;
        this.uuid = Math.random();
        this.authCallback = null;
        this.authAttempts = 0;
        this.closeCallbacks = new Set();
    }
    get isOpen() {
        return this.isClosed !== true;
    }
    flush() {
    }
    /**
     * Sends a message based on the provided action and topic
     */
    sendMessage(message, allowBuffering = true) {
        this.services.monitoring.onMessageSend(message);
        this.sendBuiltMessage(message);
    }
    /**
     * Sends a message based on the provided action and topic
     */
    sendAckMessage(message, allowBuffering = true) {
        this.services.monitoring.onMessageSend(message);
        if (message.topic === constants_1.TOPIC.EVENT) {
            if (message.action === constants_1.EVENT_ACTION.SUBSCRIBE) {
                this.socket.suback({ granted: [0], messageId: Number(message.correlationId) });
                return;
            }
        }
        if (message.topic === constants_1.TOPIC.RECORD) {
            if (message.action === constants_1.RECORD_ACTION.SUBSCRIBE) {
                this.socket.suback({ granted: [1], messageId: Number(message.correlationId) });
                return;
            }
        }
        this.logger.warn(types_1.EVENT.UNKNOWN_ACTION, `Unhandled ack message for ${constants_1.TOPIC[message.topic]}:${constants_2.ACTIONS_BYTE_TO_KEY[message.topic][message.action]}`);
    }
    getMessage(message) {
        return message;
    }
    parseData(message) {
        return true;
    }
    onMessage(messages) {
    }
    /**
     * Destroys the socket. Removes all deepstream specific
     * logic and closes the connection
     */
    destroy() {
        this.socket.destroy();
    }
    close() {
        this.isClosed = true;
        delete this.authCallback;
        this.closeCallbacks.forEach((cb) => cb(this));
        this.services.logger.info(types_1.EVENT.CLIENT_DISCONNECTED, this.userId);
    }
    parseMessage(serializedMessage) {
        return message_parser_1.parseMQTT(serializedMessage);
    }
    /**
     * Returns a map of parameters that were collected
     * during the initial http request that established the
     * connection
     */
    getHandshakeData() {
        return this.handshakeData;
    }
    onClose(callback) {
        this.closeCallbacks.add(callback);
    }
    removeOnClose(callback) {
        this.closeCallbacks.delete(callback);
    }
    sendBuiltMessage(message, buffer) {
        if (this.isOpen) {
            if (message.topic === constants_1.TOPIC.CONNECTION) {
                if (message.action === constants_1.CONNECTION_ACTION.ACCEPT) {
                    return;
                }
            }
            if (message.topic === constants_1.TOPIC.AUTH) {
                if (message.action === constants_1.AUTH_ACTION.AUTH_SUCCESSFUL) {
                    this.socket.connack({ returnCode: 0 });
                    return;
                }
                if (message.action === constants_1.AUTH_ACTION.AUTH_UNSUCCESSFUL) {
                    this.socket.connack({ returnCode: 5, reason: message.reason });
                    return;
                }
            }
            if (message.topic === constants_1.TOPIC.EVENT) {
                if (message.action === constants_1.EVENT_ACTION.EMIT) {
                    let payload = message.data;
                    if (!payload && message.parsedData) {
                        payload = Buffer.from(JSON.stringify(message.parsedData));
                    }
                    this.socket.publish({
                        cmd: 'publish',
                        topic: message.name,
                        payload,
                        length: payload && payload.length
                    });
                    return;
                }
            }
            if (message.topic === constants_1.TOPIC.RECORD) {
                if (message.action === constants_1.RECORD_ACTION.WRITE_ACKNOWLEDGEMENT) {
                    this.socket.puback({ messageId: message.correlationId });
                    return;
                }
                if (message.action === constants_1.RECORD_ACTION.UPDATE) {
                    const payload = Buffer.from(JSON.stringify(message.parsedData));
                    this.socket.publish({
                        cmd: 'publish',
                        topic: message.name,
                        payload,
                        length: payload.length
                    });
                    return;
                }
                if (message.action === constants_1.RECORD_ACTION.PATCH) {
                    this.logger.warn(types_1.EVENT.UNSUPPORTED_ACTION, 'Patches are not currently supported via the MQTT API');
                    return;
                }
            }
            this.logger.warn(types_1.EVENT.UNKNOWN_ACTION, `Unhandled message for ${constants_1.TOPIC[message.topic]}:${constants_2.ACTIONS_BYTE_TO_KEY[message.topic][message.action]}`);
        }
    }
}
exports.MQTTSocketWrapper = MQTTSocketWrapper;
exports.createMQTTSocketWrapper = function (socket, handshakeData, services, logger) { return new MQTTSocketWrapper(socket, handshakeData, services, logger); };
//# sourceMappingURL=socket-wrapper-factory.js.map