"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const events_1 = require("events");
const packet_1 = __importDefault(require("./packet"));
class ChecksumError extends Error {
    constructor(packet) {
        super();
        this.packet = packet;
        Object.setPrototypeOf(this, ChecksumError.prototype);
        this.name = 'ChecksumError';
        this.message = 'Checksum mismatch';
        Error.captureStackTrace(this, PacketReader.ChecksumError);
    }
}
class MagicError extends Error {
    constructor(packet) {
        super();
        this.packet = packet;
        Object.setPrototypeOf(this, MagicError.prototype);
        this.name = 'MagicError';
        this.message = 'Magic value mismatch';
        Error.captureStackTrace(this, PacketReader.MagicError);
    }
}
class PacketReader extends events_1.EventEmitter {
    constructor(stream) {
        super();
        this.stream = stream;
        this.inBody = false;
        this.stream.on('readable', this._tryRead.bind(this));
        this.stream.on('error', (err) => {
            return this.emit('error', err);
        });
        this.stream.on('end', () => {
            return this.emit('end');
        });
        setImmediate(this._tryRead.bind(this));
    }
    _tryRead() {
        while (this._appendChunk()) {
            while (this.buffer) {
                if (this.inBody) {
                    if (!(this.buffer.length >= this.packet.length)) {
                        break;
                    }
                    this.packet.data = this._consume(this.packet.length);
                    if (!this.packet.verifyChecksum()) {
                        this.emit('error', new PacketReader.ChecksumError(this.packet));
                        return;
                    }
                    this.emit('packet', this.packet);
                    this.inBody = false;
                }
                else {
                    if (!(this.buffer.length >= 24)) {
                        break;
                    }
                    const header = this._consume(24);
                    this.packet = new packet_1.default(header.readUInt32LE(0), header.readUInt32LE(4), header.readUInt32LE(8), header.readUInt32LE(12), header.readUInt32LE(16), header.readUInt32LE(20), Buffer.alloc(0));
                    if (!this.packet.verifyMagic()) {
                        this.emit('error', new PacketReader.MagicError(this.packet));
                        return;
                    }
                    if (this.packet.length === 0) {
                        this.emit('packet', this.packet);
                    }
                    else {
                        this.inBody = true;
                    }
                }
            }
        }
    }
    _appendChunk() {
        const chunk = this.stream.read();
        if (chunk) {
            if (this.buffer) {
                return (this.buffer = Buffer.concat([this.buffer, chunk], this.buffer.length + chunk.length));
            }
            else {
                return (this.buffer = chunk);
            }
        }
        else {
            return null;
        }
    }
    _consume(length) {
        const chunk = this.buffer.slice(0, length);
        this.buffer = length === this.buffer.length ? null : this.buffer.slice(length);
        return chunk;
    }
}
PacketReader.ChecksumError = ChecksumError;
PacketReader.MagicError = MagicError;
exports.default = PacketReader;
//# sourceMappingURL=packetreader.js.map