var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _NEF_checksum;
import { StringStream, HexString, ab2hexstring, getSerializedSize, num2hexstring, str2hexstring, num2VarInt, hash256, serializeArrayOf, } from "../u";
import { MethodToken } from "./MethodToken";
export class NEF {
    constructor(obj) {
        _NEF_checksum.set(this, void 0);
        const { compiler = "", tokens = [], script = "" } = obj;
        this.compiler = compiler;
        this.tokens = tokens.map((token) => new MethodToken(token));
        this.script = script;
    }
    get checksum() {
        if (!__classPrivateFieldGet(this, _NEF_checksum, "f")) {
            __classPrivateFieldSet(this, _NEF_checksum, this.computeCheckSum(), "f");
        }
        return __classPrivateFieldGet(this, _NEF_checksum, "f");
    }
    static fromJson(json) {
        if (json.magic !== this.MAGIC) {
            throw new Error("Incorrect magic");
        }
        const nef = new NEF({
            compiler: json.compiler,
            tokens: json.tokens.map((t) => MethodToken.fromJson(t)),
            script: json.script,
        });
        if (nef.checksum !== json.checksum) {
            throw new Error("Invalid checksum");
        }
        return nef;
    }
    static fromBuffer(data) {
        const reader = new StringStream(ab2hexstring(data));
        const magic = HexString.fromHex(reader.read(4), true).toNumber();
        if (magic !== this.MAGIC)
            throw new Error("NEF deserialization failure - incorrect magic");
        const compilerHexArray = Buffer.from(reader.read(64), "hex");
        const idx = compilerHexArray.indexOf(0x0);
        const compiler = compilerHexArray.slice(0, idx).toString();
        if (reader.read(2) !== "0000")
            throw new Error("NEF deserialization failure - reserved bytes must be 0");
        const tokenLength = reader.readVarInt();
        if (tokenLength > 128)
            throw new Error("NEF deserialization failure - token array exceeds maximum length of 128");
        const tokens = [];
        for (let i = 0; i < tokenLength; i++) {
            tokens.push(MethodToken.fromStream(reader));
        }
        if (reader.read(2) !== "0000")
            throw new Error("NEF deserialization failure - reserved bytes must be 0");
        const scriptLength = reader.readVarInt();
        if (scriptLength === 0)
            throw new Error("NEF deserialization failure - script length can't be 0");
        if (scriptLength > this.MAX_SCRIPT_LENGTH)
            throw new Error("NEF deserialization failure - max script length exceeded");
        const script = reader.read(scriptLength);
        const checksum = Buffer.from(reader.read(4), "hex").readUInt32LE();
        const nef = new NEF({
            compiler: compiler,
            tokens: tokens,
            script: script,
        });
        if (nef.checksum !== checksum) {
            throw new Error("NEF deserialization failure - invalid checksum");
        }
        return nef;
    }
    toJson() {
        return {
            magic: NEF.MAGIC,
            compiler: this.compiler,
            tokens: this.tokens.map((t) => t.toJson()),
            script: this.script,
            checksum: this.checksum,
        };
    }
    get size() {
        return (32 + // magic
            64 + // compiler
            2 + // reserved
            getSerializedSize(this.tokens) +
            2 + // reserved
            getSerializedSize(HexString.fromHex(this.script)) +
            4); // checksum
    }
    serializeWithoutChecksum() {
        let out = "";
        out += num2hexstring(NEF.MAGIC, 4, true);
        out += str2hexstring(this.compiler).padEnd(128, "0");
        out += "0000"; // reserved
        out += serializeArrayOf(this.tokens);
        out += "0000"; // reserved
        out += num2VarInt(this.script.length / 2);
        out += this.script;
        return out;
    }
    serialize() {
        let out = this.serializeWithoutChecksum();
        out += num2hexstring(this.checksum, 4, true);
        return out;
    }
    export() {
        return {
            compiler: this.compiler,
            tokens: this.tokens.map((t) => t.export()),
            script: this.script,
        };
    }
    computeCheckSum() {
        const data = this.serializeWithoutChecksum();
        const hash = hash256(data);
        return Buffer.from(hash, "hex").readUInt32LE();
    }
}
_NEF_checksum = new WeakMap();
NEF.MAX_SCRIPT_LENGTH = 512 * 1024;
NEF.MAGIC = 0x3346454e;
export default NEF;
//# sourceMappingURL=NEF.js.map