"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReaderUint8Array = void 0;
const BigNumber_js_1 = __importDefault(require("./BigNumber.js"));
const utils_js_1 = require("./utils.js");
/**
 * Reader for serialized Uint8Array binary data.
 */
class ReaderUint8Array {
    static makeReader(bin, pos = 0) {
        if (bin instanceof Uint8Array) {
            return new ReaderUint8Array(bin, pos);
        }
        if (Array.isArray(bin)) {
            return new utils_js_1.Reader(bin, pos);
        }
        throw new Error('ReaderUint8Array.makeReader: bin must be Uint8Array or number[]');
    }
    constructor(bin = new Uint8Array(0), pos = 0) {
        if (bin instanceof Uint8Array) {
            this.bin = bin;
        }
        else if (Array.isArray(bin)) {
            this.bin = new Uint8Array(bin);
        }
        else {
            throw new TypeError('ReaderUint8Array constructor: bin must be Uint8Array or number[]');
        }
        this.pos = pos;
        this.length = this.bin.length;
    }
    eof() {
        return this.pos >= this.length;
    }
    read(len = this.length) {
        const start = this.pos;
        const end = this.pos + len;
        this.pos = end;
        return this.bin.slice(start, end);
    }
    readReverse(len = this.length) {
        const buf2 = new Uint8Array(len);
        for (let i = 0; i < len; i++) {
            buf2[i] = this.bin[this.pos + len - 1 - i];
        }
        this.pos += len;
        return buf2;
    }
    readUInt8() {
        const val = this.bin[this.pos];
        this.pos += 1;
        return val;
    }
    readInt8() {
        const val = this.bin[this.pos];
        this.pos += 1;
        // If the sign bit is set, convert to negative value
        return (val & 0x80) === 0 ? val : val - 0x100;
    }
    readUInt16BE() {
        const val = (this.bin[this.pos] << 8) | this.bin[this.pos + 1];
        this.pos += 2;
        return val;
    }
    readInt16BE() {
        const val = this.readUInt16BE();
        // If the sign bit is set, convert to negative value
        return (val & 0x8000) === 0 ? val : val - 0x10000;
    }
    readUInt16LE() {
        const val = this.bin[this.pos] | (this.bin[this.pos + 1] << 8);
        this.pos += 2;
        return val;
    }
    readInt16LE() {
        const val = this.readUInt16LE();
        // If the sign bit is set, convert to negative value
        const x = (val & 0x8000) === 0 ? val : val - 0x10000;
        return x;
    }
    readUInt32BE() {
        const val = this.bin[this.pos] * 0x1000000 + // Shift the first byte by 24 bits
            ((this.bin[this.pos + 1] << 16) | // Shift the second byte by 16 bits
                (this.bin[this.pos + 2] << 8) | // Shift the third byte by 8 bits
                this.bin[this.pos + 3]); // The fourth byte
        this.pos += 4;
        return val;
    }
    readInt32BE() {
        const val = this.readUInt32BE();
        // If the sign bit is set, convert to negative value
        return (val & 0x80000000) === 0 ? val : val - 0x100000000;
    }
    readUInt32LE() {
        const val = (this.bin[this.pos] |
            (this.bin[this.pos + 1] << 8) |
            (this.bin[this.pos + 2] << 16) |
            (this.bin[this.pos + 3] << 24)) >>>
            0;
        this.pos += 4;
        return val;
    }
    readInt32LE() {
        const val = this.readUInt32LE();
        // Explicitly check if the sign bit is set and then convert to a negative value
        return (val & 0x80000000) === 0 ? val : val - 0x100000000;
    }
    readUInt64BEBn() {
        const bin = Array.from(this.bin.slice(this.pos, this.pos + 8));
        const bn = new BigNumber_js_1.default(bin);
        this.pos = this.pos + 8;
        return bn;
    }
    readUInt64LEBn() {
        const bin = Array.from(this.readReverse(8));
        const bn = new BigNumber_js_1.default(bin);
        return bn;
    }
    readInt64LEBn() {
        const OverflowInt64 = new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(63));
        const OverflowUint64 = new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(64));
        const bin = Array.from(this.readReverse(8));
        let bn = new BigNumber_js_1.default(bin);
        if (bn.gte(OverflowInt64)) {
            bn = bn.sub(OverflowUint64); // Adjust for negative numbers
        }
        return bn;
    }
    readVarIntNum(signed = true) {
        const first = this.readUInt8();
        let bn;
        switch (first) {
            case 0xfd:
                return this.readUInt16LE();
            case 0xfe:
                return this.readUInt32LE();
            case 0xff:
                bn = signed ? this.readInt64LEBn() : this.readUInt64LEBn();
                if (bn.lte(new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(53)))) {
                    return bn.toNumber();
                }
                else {
                    throw new Error('number too large to retain precision - use readVarIntBn');
                }
            default:
                return first;
        }
    }
    readVarInt() {
        const first = this.bin[this.pos];
        switch (first) {
            case 0xfd:
                return this.read(1 + 2);
            case 0xfe:
                return this.read(1 + 4);
            case 0xff:
                return this.read(1 + 8);
            default:
                return this.read(1);
        }
    }
    readVarIntBn() {
        const first = this.readUInt8();
        switch (first) {
            case 0xfd:
                return new BigNumber_js_1.default(this.readUInt16LE());
            case 0xfe:
                return new BigNumber_js_1.default(this.readUInt32LE());
            case 0xff:
                return this.readUInt64LEBn();
            default:
                return new BigNumber_js_1.default(first);
        }
    }
}
exports.ReaderUint8Array = ReaderUint8Array;
//# sourceMappingURL=ReaderUint8Array.js.map