"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;
        console.debug("forward() Forward to bit " + this._offset);
        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);
        }
        // console.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; }
        console.debug("getUintX");
        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);
        console.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;
            console.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;
        }
        console.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; }
        console.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;
/**********************************************************
 *
 * BitStream
 *
 * Small wrapper for a BitView to maintain your position,
 * as well as to handle reading / writing of string data
 * to the underlying buffer.
 *
 **********************************************************/
// var reader = function (name, size) {
//     return function () {
//         if (this._index + size > this._length) {
//             throw new Error('Trying to read past the end of the stream');
//         }
//         var val = this._view[name](this._index);
//         this._index += size;
//         return val;
//     }
// }
// var writer = function (name, size) {
//     return function (value) {
//         this._view[name](this._index, value);
//         this._index += size;
//     }
// }
// function readASCIIString(stream, bytes) {
//     return readString(stream, bytes, false);
// }
// function readUTF8String(stream, bytes) {
//     return readString(stream, bytes, true);
// }
// function readString(stream, bytes, utf8) {
//     if (bytes === 0) {
//         return '';
//     }
//     var i = 0;
//     var chars = [];
//     var append = true;
//     var fixedLength = !!bytes;
//     if (!bytes) {
//         bytes = Math.floor((stream._length - stream._index) / 8);
//     }
//     // Read while we still have space available, or until we've
//     // hit the fixed byte length passed in.
//     while (i < bytes) {
//         var c = stream.readUint8();
//         // Stop appending chars once we hit 0x00
//         if (c === 0x00) {
//             append = false;
//             // If we don't have a fixed length to read, break out now.
//             if (!fixedLength) {
//                 break;
//             }
//         }
//         if (append) {
//             chars.push(c);
//         }
//         i++;
//     }
//     var string = String.fromCharCode.apply(null, chars);
//     if (utf8) {
//         try {
//             return decodeURIComponent(escape(string)); // https://stackoverflow.com/a/17192845
//         } catch (e) {
//             return string;
//         }
//     } else {
//         return string;
//     }
// }
// function writeASCIIString(stream, string, bytes) {
//     var length = bytes || string.length + 1;  // + 1 for NULL
//     for (var i = 0; i < length; i++) {
//         stream.writeUint8(i < string.length ? string.charCodeAt(i) : 0x00);
//     }
// }
// function writeUTF8String(stream, string, bytes) {
//     var byteArray = stringToByteArray(string);
//     var length = bytes || byteArray.length + 1;  // + 1 for NULL
//     for (var i = 0; i < length; i++) {
//         stream.writeUint8(i < byteArray.length ? byteArray[i] : 0x00);
//     }
// }
// function stringToByteArray(str) { // https://gist.github.com/volodymyr-mykhailyk/2923227
//     var b = [], i, unicode;
//     for (i = 0; i < str.length; i++) {
//         unicode = str.charCodeAt(i);
//         // 0x00000000 - 0x0000007f -> 0xxxxxxx
//         if (unicode <= 0x7f) {
//             b.push(unicode);
//             // 0x00000080 - 0x000007ff -> 110xxxxx 10xxxxxx
//         } else if (unicode <= 0x7ff) {
//             b.push((unicode >> 6) | 0xc0);
//             b.push((unicode & 0x3F) | 0x80);
//             // 0x00000800 - 0x0000ffff -> 1110xxxx 10xxxxxx 10xxxxxx
//         } else if (unicode <= 0xffff) {
//             b.push((unicode >> 12) | 0xe0);
//             b.push(((unicode >> 6) & 0x3f) | 0x80);
//             b.push((unicode & 0x3f) | 0x80);
//             // 0x00010000 - 0x001fffff -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
//         } else {
//             b.push((unicode >> 18) | 0xf0);
//             b.push(((unicode >> 12) & 0x3f) | 0x80);
//             b.push(((unicode >> 6) & 0x3f) | 0x80);
//             b.push((unicode & 0x3f) | 0x80);
//         }
//     }
//     return b;
// }
// var BitStream = function (source, byteOffset, byteLength) {
//     var isBuffer = source instanceof ArrayBuffer ||
//         (typeof Buffer !== 'undefined' && source instanceof Buffer);
//     if (!(source instanceof BitView) && !isBuffer) {
//         throw new Error('Must specify a valid BitView, ArrayBuffer or Buffer');
//     }
//     if (isBuffer) {
//         this._view = new BitView(source, byteOffset, byteLength);
//     } else {
//         this._view = source;
//     }
//     this._index = 0;
//     this._startIndex = 0;
//     this._length = this._view.byteLength * 8;
// }
// Object.defineProperty(BitStream.prototype, 'index', {
//     get: function () { return this._index - this._startIndex; },
//     set: function (val) { this._index = val + this._startIndex; },
//     enumerable: true,
//     configurable: true
// });
// Object.defineProperty(BitStream.prototype, 'length', {
//     get: function () { return this._length - this._startIndex; },
//     set: function (val) { this._length = val + this._startIndex; },
//     enumerable  : true,
//     configurable: true
// });
// Object.defineProperty(BitStream.prototype, 'bitsLeft', {
//     get: function () { return this._length - this._index; },
//     enumerable  : true,
//     configurable: true
// });
// Object.defineProperty(BitStream.prototype, 'byteIndex', {
//     // Ceil the returned value, over compensating for the amount of
//     // bits written to the stream.
//     get: function () { return Math.ceil(this._index / 8); },
//     set: function (val) { this._index = val * 8; },
//     enumerable: true,
//     configurable: true
// });
// Object.defineProperty(BitStream.prototype, 'buffer', {
//     get: function () { return this._view.buffer; },
//     enumerable: true,
//     configurable: false
// });
// Object.defineProperty(BitStream.prototype, 'view', {
//     get: function () { return this._view; },
//     enumerable: true,
//     configurable: false
// });
// BitStream.prototype.readBits = function (bits, signed) {
//     var val = this._view.getBits(this._index, bits, signed);
//     this._index += bits;
//     return val;
// }
// BitStream.prototype.writeBits = function (value, bits) {
//     this._view.setBits(this._index, value, bits);
//     this._index += bits;
// }
// BitStream.prototype.readBoolean = reader('getBoolean', 1);
// BitStream.prototype.readInt8 = reader('getInt8', 8);
// BitStream.prototype.readUint8 = reader('getUint8', 8);
// BitStream.prototype.readInt16 = reader('getInt16', 16);
// BitStream.prototype.readUint16 = reader('getUint16', 16);
// BitStream.prototype.readInt32 = reader('getInt32', 32);
// BitStream.prototype.readUint32 = reader('getUint32', 32);
// BitStream.prototype.readFloat32 = reader('getFloat32', 32);
// BitStream.prototype.readFloat64 = reader('getFloat64', 64);
// BitStream.prototype.writeBoolean = writer('setBoolean', 1);
// BitStream.prototype.writeInt8 = writer('setInt8', 8);
// BitStream.prototype.writeUint8 = writer('setUint8', 8);
// BitStream.prototype.writeInt16 = writer('setInt16', 16);
// BitStream.prototype.writeUint16 = writer('setUint16', 16);
// BitStream.prototype.writeInt32 = writer('setInt32', 32);
// BitStream.prototype.writeUint32 = writer('setUint32', 32);
// BitStream.prototype.writeFloat32 = writer('setFloat32', 32);
// BitStream.prototype.writeFloat64 = writer('setFloat64', 64);
// BitStream.prototype.readASCIIString = function (bytes) {
//     return readASCIIString(this, bytes);
// }
// BitStream.prototype.readUTF8String = function (bytes) {
//     return readUTF8String(this, bytes);
// }
// BitStream.prototype.writeASCIIString = function (string, bytes) {
//     writeASCIIString(this, string, bytes);
// }
// BitStream.prototype.writeUTF8String = function (string, bytes) {
//     writeUTF8String(this, string, bytes);
// }
// BitStream.prototype.readBitStream = function(bitLength) {
//     var slice = new BitStream(this._view);
//     slice._startIndex = this._index;
//     slice._index = this._index;
//     slice.length = bitLength;
//     this._index += bitLength;
//     return slice;
// }
// BitStream.prototype.writeBitStream = function(stream, length) {
//     if (!length) {
//         length = stream.bitsLeft;
//     }
//     var bitsToWrite;
//     while (length > 0) {
//         bitsToWrite = Math.min(length, 32);
//         this.writeBits(stream.readBits(bitsToWrite), bitsToWrite);
//         length -= bitsToWrite;
//     }
// }
// BitStream.prototype.readArrayBuffer = function(byteLength) {
//     var buffer = this._view.getArrayBuffer(this._index, byteLength);
//     this._index += (byteLength * 8);
//     return buffer;
// }
// BitStream.prototype.writeArrayBuffer = function(buffer, byteLength) {
//     this.writeBitStream(new BitStream(buffer), byteLength * 8);
// }
// // AMD / RequireJS
// if (typeof define !== 'undefined' && define.amd) {
//     define(function () {
//         return {
//             BitView: BitView,
//             BitStream: BitStream
//         }
//     });
// }
// // Node.js
// else if (typeof module !== 'undefined' && module.exports) {
//     module.exports = {
//         BitView: BitView,
//         BitStream: BitStream
//     }
// }
