"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * @deprecated Use kaitai instead
 */
var BitBuffer = /** @class */ (function () {
    function BitBuffer(source, lastOffset) {
        this._leastSignificantBitFirst = false; // TODO USE
        // Used to massage fp values so we can operate on them
        // at the bit level.
        this._scratch = new DataView(new ArrayBuffer(8));
        this._view = source;
        this._offset = 0;
    }
    Object.defineProperty(BitBuffer.prototype, "offset", {
        get: function () {
            return this._offset;
        },
        enumerable: true,
        configurable: true
    });
    BitBuffer.minSizeToFitBits = function (nbBits) {
        return (nbBits / 8) + (nbBits % 8 > 0 ? 1 : 0);
    };
    BitBuffer.create = function (nbBits) {
        return new BitBuffer(new Uint8Array(BitBuffer.minSizeToFitBits(nbBits)));
    };
    BitBuffer.prototype.sizeInBits = function () {
        return this._view.byteLength * 8; // TODO not full size..
    };
    BitBuffer.prototype.view = function () {
        return this._view;
    };
    BitBuffer.prototype.seekTo = function (offset) {
        this._offset = offset;
        return this;
    };
    BitBuffer.prototype.forward = function (nbBits) {
        if (nbBits === void 0) { nbBits = 1; }
        this._offset += nbBits;
        return this;
    };
    BitBuffer.prototype._setBit = function (on) {
        // this._offset >> 3 will give the block
        // 
        var bitMask = 1 << (7 - (this._offset & 7));
        if (on) {
            this._view[this._offset >> 3] |= bitMask;
        }
        else {
            this._view[this._offset >> 3] &= ~(bitMask);
        }
        // logger.debug(`_setBit ${this._offset} to ${on} (block ${this._offset >> 3}; mask=${bitMask})`);
        this._offset++;
    };
    BitBuffer.prototype.getUintX = function (nbBits, signed, offset) {
        if (signed === void 0) { signed = false; }
        return this.getBits(nbBits, signed, offset);
    };
    BitBuffer.prototype.fromOffsetLessNumber = function (nbBits) {
        return this.getArrayBuffer(this._offset - nbBits, Math.ceil(nbBits / 8));
    };
    // public static getMask(offset: number, nbBits: number){
    //     var remaining = (offset+nbBits) & 0b111;
    //     var 
    // }
    BitBuffer.prototype.getBits = function (nbBits, signed, offset) {
        var callOffset = typeof offset === "undefined" ? this._offset : offset;
        var available = (this._view.length * 8 - callOffset);
        // logger.debug(`getBits ${callOffset} to ${callOffset + nbBits -1} (available=${available}; signed=${signed}) ${typeof offset === "undefined"}`);
        if (nbBits > available) {
            throw new Error('Cannot get ' + nbBits + ' bit(s) from offset ' + callOffset + ', ' + available + ' available');
        }
        var value = 0;
        for (var i = 0; i < nbBits; i += read) {
            var remaining = nbBits - i;
            var bitOffset = callOffset & 7;
            var currentByte = this._view[callOffset >> 3];
            // the max number of bits we can read from the current byte
            var read = Math.min(remaining, 8 - bitOffset);
            var mask = (0xFF >> bitOffset) & 0xFF;
            var stripRight = (8 - read - bitOffset);
            // create a mask with the correct bit width
            mask &= 0xFF << stripRight;
            // shift the bits we want to the start of the byte and mask of the rest
            var readBits = (currentByte & mask) >> stripRight;
            // logger.debug(`Mask will be ${mask} (i=${i};stripRight=${stripRight};stripLeft=${bitOffset};readBits=${readBits}; read=${read}; current byte index: ${callOffset >> 3}; current byte value: ${currentByte}; remaining=${remaining}; callOffset=${callOffset}/${nbBits})`);
            // if (this._leastSignificantBitFirst){
            //     value |= readBits << i;
            // }
            // else {
            //     value |= readBits << (nbBits - i - (8-bitOffset));
            // }
            value = (value << 8) | readBits;
            callOffset += read;
        }
        if (typeof offset === "undefined") {
            this.forward(nbBits);
        }
        if (signed) {
            // If we're not working with a full 32 bits, check the
            // imaginary MSB for this bit count and convert to a
            // valid 32-bit signed value if set.
            if (nbBits !== 32 && value & (1 << (nbBits - 1))) {
                value |= -1 ^ ((1 << nbBits) - 1);
            }
            return value;
        }
        // logger.debug(`getBits Value read: ${value} on ${nbBits} bits. offset is now ${this._offset}`);
        return value >>> 0;
    };
    BitBuffer.prototype.append = function (data, nbBits, fromLeftBits) {
        if (fromLeftBits === void 0) { fromLeftBits = false; }
        // logger.debug(`BitBuffer append ${data} on ${nbBits} bits`);
        if (typeof nbBits === "undefined") {
            nbBits = data.byteLength * 8;
        }
        var length8 = (nbBits >> 3) + 1;
        var remaining = nbBits & 7;
        for (var i = 0; i < length8 - 1; i++) {
            this.setBits(data[i], 8);
        }
        this.setBits(data[length8 - 1] >> (fromLeftBits ? (8 - remaining) : 0), remaining);
    };
    /**
     * TODO
     * @param value
     * @param nbBits
     */
    BitBuffer.prototype.setBits = function (value, nbBits) {
        for (var i = nbBits - 1; i >= 0; i--) {
            this._setBit((value >> i) & 0x1 ? true : false);
        }
    };
    BitBuffer.prototype.getBoolean = function (offset) {
        return this.getBits(1, false, offset) !== 0;
    };
    BitBuffer.prototype.getInt8 = function (offset) {
        return this.getBits(8, true, offset);
    };
    BitBuffer.prototype.getUint8 = function (offset) {
        return this.getBits(8, false, offset);
    };
    BitBuffer.prototype.getInt16 = function (offset) {
        return this.getBits(16, true, offset);
    };
    BitBuffer.prototype.getUint16 = function (offset) {
        return this.getBits(16, false, offset);
    };
    BitBuffer.prototype.getInt32 = function (offset) {
        return this.getBits(32, true, offset);
    };
    BitBuffer.prototype.getUint32 = function (offset) {
        return this.getBits(32, false, offset) >>> 0;
    };
    BitBuffer.prototype.getFloat32 = function (offset) {
        this._scratch.setUint32(0, this.getUint32(offset));
        return this._scratch.getFloat32(0);
    };
    BitBuffer.prototype.getFloat64 = function (offset) {
        if (offset === void 0) { offset = 0; }
        this._scratch.setUint32(0, this.getUint32(offset));
        // DataView offset is in bytes.
        this._scratch.setUint32(4, this.getUint32(offset + 32));
        return this._scratch.getFloat64(0);
    };
    BitBuffer.prototype.setBoolean = function (value) {
        this.setBits(value ? 1 : 0, 1);
    };
    // public setInt8  =
    BitBuffer.prototype.setUint8 = function (value) {
        this.setBits(value, 8);
    };
    // public setInt16  =
    BitBuffer.prototype.setUint16 = function (value) {
        this.setBits(value, 16);
    };
    // public setInt32  =
    BitBuffer.prototype.setUint32 = function (value) {
        this.setBits(value, 32);
    };
    BitBuffer.prototype.setFloat32 = function (value) {
        this._scratch.setFloat32(0, value);
        this.setBits(this._scratch.getUint32(0), 32);
    };
    BitBuffer.prototype.setFloat64 = function (value) {
        this._scratch.setFloat64(0, value);
        this.setBits(this._scratch.getUint32(0), 32);
        this.setBits(this._scratch.getUint32(4), 32);
    };
    BitBuffer.prototype.getArrayBuffer = function (offset, byteLength) {
        var buffer = new Uint8Array(byteLength);
        for (var i = 0; i < byteLength; i++) {
            buffer[i] = this.getUint8(offset + (i * 8));
        }
        return buffer;
    };
    return BitBuffer;
}());
exports.BitBuffer = BitBuffer;
