"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VideohubConnection = exports.ConnectionStatus = void 0;
const net = require("net");
const events_1 = require("events");
const Command_1 = require("./Command");
const PING_INTERVAL = 5000;
var ConnectionStatus;
(function (ConnectionStatus) {
    ConnectionStatus["Idle"] = "IDLE";
    ConnectionStatus["Connecting"] = "CONNECTING";
    ConnectionStatus["Connected"] = "CONNECTED";
})(ConnectionStatus || (exports.ConnectionStatus = ConnectionStatus = {}));
// tslint:disable-next-line:no-console
const debug = console.log;
class VideohubConnection extends events_1.EventEmitter {
    constructor(host) {
        super();
        this.RECONNECT_TIMEOUT = 500;
        this.pingInterval = null;
        this.socket = undefined;
        this.command = null;
        this.stash = [];
        this.status = ConnectionStatus.Idle;
        this.config = {
            host,
            port: 9990
        };
    }
    getStatus() {
        return this.status;
    }
    connect() {
        if (!this.socket) {
            this.createSocket();
        }
        if (this.socket) {
            this.socket.connect(this.config.port, this.config.host);
            this.status = ConnectionStatus.Connecting;
        }
    }
    send(command) {
        if (this.socket !== undefined && command !== undefined) {
            try {
                this.socket.write(command.format());
            }
            catch (e) {
                debug(e);
            }
        }
    }
    deleteSocket() {
        if (this.socket !== undefined) {
            this.socket.destroy();
            delete this.socket;
        }
        if (this.pingInterval !== null) {
            clearInterval(this.pingInterval);
            this.pingInterval = null;
        }
    }
    createSocket() {
        let receivebuffer = '';
        this.deleteSocket();
        if (this.config.port === undefined) {
            this.config.port = 9990;
        }
        if (this.config.host) {
            this.socket = new net.Socket();
            this.socket.setKeepAlive(true);
            this.socket.setNoDelay(true);
            this.socket.on('connect', () => {
                this.status = ConnectionStatus.Connected;
                this.pingInterval = setInterval(() => {
                    this.send(new Command_1.VideohubCommand('PING'));
                }, PING_INTERVAL);
            });
            this.socket.on('error', (err) => {
                this.deleteSocket();
                this.status = ConnectionStatus.Idle;
                this.emit('debug', err);
                setTimeout(() => this.connect(), this.RECONNECT_TIMEOUT);
            });
            this.socket.on('end', () => {
                this.deleteSocket();
                this.status = ConnectionStatus.Idle;
                setTimeout(() => this.connect(), this.RECONNECT_TIMEOUT);
            });
            // separate buffered stream into lines with responses
            this.socket.on('data', (chunk) => {
                let i = 0;
                let line = '';
                let offset = 0;
                receivebuffer += chunk;
                // tslint:disable-next-line:no-conditional-assignment
                while ((i = receivebuffer.indexOf('\n', offset)) !== -1) {
                    line = receivebuffer.substr(offset, i - offset);
                    offset = i + 1;
                    if (this.socket !== undefined) {
                        this.socket.emit('receiveline', line.toString());
                    }
                }
                receivebuffer = receivebuffer.substr(offset);
            });
            this.socket.on('receiveline', (line) => {
                if (this.command === null && line.match(/:/)) {
                    this.command = line;
                }
                else if (this.command === null && line.trim() === 'ACK') {
                    this.emit('ack');
                }
                else if (this.command === null && line.trim() === 'NAK') {
                    this.emit('nak');
                }
                else if (this.command !== null && line.length > 0) {
                    this.stash.push(line.trim());
                }
                else if (line.length === 0 && this.command !== null) {
                    const cmd = this.command.trim().split(/:/)[0];
                    this.emit('data', cmd, this.stash);
                    this.stash = [];
                    this.command = null;
                }
                else if (line.length > 0) {
                    debug('weird response from videohub', line, line.length);
                }
            });
        }
    }
}
exports.VideohubConnection = VideohubConnection;
//# sourceMappingURL=Connection.js.map