import * as operations from '../../operations';
import { Timestamp } from '../../clock';
import { toBase64 } from '@jsonjoy.com/base64/lib/toBase64';
const timestamp = (sid, ts) => {
    const tsSessionId = ts.sid;
    return tsSessionId === sid ? ts.time : [tsSessionId, ts.time];
};
const timespan = (sid, span) => {
    const ts = timestamp(sid, span);
    if (Array.isArray(ts)) {
        ts.push(span.span);
        return ts;
    }
    return [ts, span.span];
};
/**
 * Encodes a patch into a compact binary format into a JavaScript array.
 *
 * @param patch The patch to encode.
 * @returns The encoded patch as a JavaScript POJO.
 */
export const encode = (patch) => {
    const id = patch.getId();
    if (!id)
        throw new Error('PATCH_EMPTY');
    const sid = id.sid;
    const time = id.time;
    const header = sid === 1 /* SESSION.SERVER */ ? [time] : [[sid, time]];
    const meta = patch.meta;
    if (meta !== undefined)
        header.push(meta);
    const res = [header];
    for (const op of patch.ops) {
        if (op instanceof operations.NewConOp) {
            const val = op.val;
            if (val instanceof Timestamp) {
                res.push([0 /* JsonCrdtPatchOpcode.new_con */, timestamp(sid, val), true]);
            }
            else if (val === undefined) {
                res.push([0 /* JsonCrdtPatchOpcode.new_con */]);
            }
            else {
                res.push([0 /* JsonCrdtPatchOpcode.new_con */, val]);
            }
        }
        else if (op instanceof operations.NewValOp) {
            res.push([1 /* JsonCrdtPatchOpcode.new_val */]);
        }
        else if (op instanceof operations.NewObjOp) {
            res.push([2 /* JsonCrdtPatchOpcode.new_obj */]);
        }
        else if (op instanceof operations.NewVecOp) {
            res.push([3 /* JsonCrdtPatchOpcode.new_vec */]);
        }
        else if (op instanceof operations.NewStrOp) {
            res.push([4 /* JsonCrdtPatchOpcode.new_str */]);
        }
        else if (op instanceof operations.NewBinOp) {
            res.push([5 /* JsonCrdtPatchOpcode.new_bin */]);
        }
        else if (op instanceof operations.NewArrOp) {
            res.push([6 /* JsonCrdtPatchOpcode.new_arr */]);
        }
        else if (op instanceof operations.InsValOp) {
            res.push([9 /* JsonCrdtPatchOpcode.ins_val */, timestamp(sid, op.obj), timestamp(sid, op.val)]);
        }
        else if (op instanceof operations.InsObjOp) {
            const tuples = [];
            for (const [key, value] of op.data)
                tuples.push([key, timestamp(sid, value)]);
            const operation = [
                10 /* JsonCrdtPatchOpcode.ins_obj */,
                timestamp(sid, op.obj),
                tuples,
            ];
            res.push(operation);
        }
        else if (op instanceof operations.InsVecOp) {
            const tuples = [];
            for (const [key, value] of op.data)
                tuples.push([key, timestamp(sid, value)]);
            const operation = [
                11 /* JsonCrdtPatchOpcode.ins_vec */,
                timestamp(sid, op.obj),
                tuples,
            ];
            res.push(operation);
        }
        else if (op instanceof operations.InsStrOp) {
            const operation = [
                12 /* JsonCrdtPatchOpcode.ins_str */,
                timestamp(sid, op.obj),
                timestamp(sid, op.ref),
                op.data,
            ];
            res.push(operation);
        }
        else if (op instanceof operations.InsBinOp) {
            const operation = [
                13 /* JsonCrdtPatchOpcode.ins_bin */,
                timestamp(sid, op.obj),
                timestamp(sid, op.ref),
                toBase64(op.data),
            ];
            res.push(operation);
        }
        else if (op instanceof operations.InsArrOp) {
            const elements = [];
            for (const element of op.data)
                elements.push(timestamp(sid, element));
            const operation = [
                14 /* JsonCrdtPatchOpcode.ins_arr */,
                timestamp(sid, op.obj),
                timestamp(sid, op.ref),
                elements,
            ];
            res.push(operation);
        }
        else if (op instanceof operations.UpdArrOp) {
            const operation = [
                15 /* JsonCrdtPatchOpcode.upd_arr */,
                timestamp(sid, op.obj),
                timestamp(sid, op.ref),
                timestamp(sid, op.val),
            ];
            res.push(operation);
        }
        else if (op instanceof operations.DelOp) {
            const operation = [
                16 /* JsonCrdtPatchOpcode.del */,
                timestamp(sid, op.obj),
                op.what.map((span) => timespan(sid, span)),
            ];
            res.push(operation);
        }
        else if (op instanceof operations.NopOp) {
            const operation = [17 /* JsonCrdtPatchOpcode.nop */];
            const len = op.len;
            if (len > 1)
                operation.push(len);
            res.push(operation);
        }
    }
    return res;
};
//# sourceMappingURL=encode.js.map