"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ViewDecoder = void 0;
const CborDecoderBase_1 = require("@jsonjoy.com/json-pack/lib/cbor/CborDecoderBase");
const CrdtReader_1 = require("../../../../json-crdt-patch/util/binary/CrdtReader");
const constants_1 = require("./constants");
class ViewDecoder extends CborDecoderBase_1.CborDecoderBase {
    constructor() {
        super(new CrdtReader_1.CrdtReader());
        this.time = -1;
    }
    decode(data) {
        const reader = this.reader;
        this.time = -1;
        reader.reset(data);
        const isServerTime = reader.peak() & 0b10000000;
        if (isServerTime) {
            reader.x++;
            this.time = reader.vu57();
        }
        else {
            reader.x += 4;
        }
        return this.cRoot();
    }
    ts() {
        if (this.time < 0)
            this.reader.idSkip();
        else
            this.reader.vu57Skip();
    }
    cRoot() {
        const reader = this.reader;
        const peek = reader.uint8[reader.x];
        return !peek ? undefined : this.cNode();
    }
    cNode() {
        const reader = this.reader;
        this.ts();
        const octet = reader.u8();
        const major = octet >> 5;
        const minor = octet & 0b11111;
        const length = minor < 0b11111 ? minor : reader.vu57();
        switch (major) {
            case constants_1.CRDT_MAJOR.CON:
                return this.cCon(length);
            case constants_1.CRDT_MAJOR.VAL:
                return this.cNode();
            case constants_1.CRDT_MAJOR.VEC:
                return this.cVec(length);
            case constants_1.CRDT_MAJOR.OBJ:
                return this.cObj(length);
            case constants_1.CRDT_MAJOR.STR:
                return this.cStr(length);
            case constants_1.CRDT_MAJOR.BIN:
                return this.cBin(length);
            case constants_1.CRDT_MAJOR.ARR:
                return this.cArr(length);
        }
        return undefined;
    }
    cCon(length) {
        return !length ? this.val() : (this.ts(), null);
    }
    cObj(length) {
        const obj = {};
        for (let i = 0; i < length; i++) {
            const key = this.key();
            const value = this.cNode();
            if (value !== undefined)
                obj[key] = value;
        }
        return obj;
    }
    cVec(length) {
        const reader = this.reader;
        const obj = [];
        for (let i = 0; i < length; i++) {
            const octet = reader.peak();
            if (!octet) {
                reader.x++;
                obj.push(undefined);
            }
            else
                obj.push(this.cNode());
        }
        return obj;
    }
    cStr(length) {
        let str = '';
        for (let i = 0; i < length; i++) {
            this.ts();
            const val = this.val();
            if (typeof val === 'string')
                str += val;
        }
        return str;
    }
    cBin(length) {
        const reader = this.reader;
        const buffers = [];
        let totalLength = 0;
        for (let i = 0; i < length; i++) {
            this.ts();
            const [deleted, length] = reader.b1vu56();
            if (deleted)
                continue;
            buffers.push(reader.buf(length));
            totalLength += length;
        }
        const res = new Uint8Array(totalLength);
        let offset = 0;
        for (let i = 0; i < buffers.length; i++) {
            const byteLength = buffers[i].length;
            res.set(buffers[i], offset);
            offset += byteLength;
        }
        return res;
    }
    cArr(length) {
        const arr = [];
        for (let i = 0; i < length; i++) {
            const values = this.cArrChunk();
            if (values && values.length)
                arr.push(...values);
        }
        return arr;
    }
    cArrChunk() {
        this.ts();
        const [deleted, length] = this.reader.b1vu56();
        if (deleted) {
            return undefined;
        }
        else {
            const values = [];
            for (let i = 0; i < length; i++)
                values.push(this.cNode());
            return values;
        }
    }
}
exports.ViewDecoder = ViewDecoder;
//# sourceMappingURL=ViewDecoder.js.map