"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NopOp = exports.DelOp = exports.UpdArrOp = exports.InsArrOp = exports.InsBinOp = exports.InsStrOp = exports.InsVecOp = exports.InsObjOp = exports.InsValOp = exports.NewArrOp = exports.NewBinOp = exports.NewStrOp = exports.NewVecOp = exports.NewObjOp = exports.NewValOp = exports.NewConOp = void 0;
const printTree_1 = require("tree-dump/lib/printTree");
const clock_1 = require("./clock");
class Op {
    constructor(id) {
        this.id = id;
    }
    span() {
        return 1;
    }
    toString() {
        let str = this.name() + ' ' + (0, clock_1.printTs)(this.id);
        const span = this.span();
        if (span > 1)
            str += '!' + span;
        return str;
    }
}
/**
 * Operation which creates a constant "con" data type.
 *
 * @category Operations
 */
class NewConOp extends Op {
    constructor(id, val) {
        super(id);
        this.id = id;
        this.val = val;
    }
    name() {
        return 'new_con';
    }
    toString() {
        const val = this.val;
        const klass = 'Uint8Array';
        const valFormatted = val instanceof clock_1.Timestamp
            ? `{ ${(0, clock_1.printTs)(val)} }`
            : val instanceof Uint8Array
                ? val.length < 13
                    ? `${klass} { ${('' + val).replaceAll(',', ', ')} }`
                    : `${klass}(${val.length})`
                : `{ ${JSON.stringify(val)} }`;
        return super.toString() + ' ' + valFormatted;
    }
}
exports.NewConOp = NewConOp;
/**
 * Operation which creates a new value object.
 *
 * @category Operations
 */
class NewValOp extends Op {
    name() {
        return 'new_val';
    }
}
exports.NewValOp = NewValOp;
/**
 * Operation which creates a new object.
 *
 * @category Operations
 */
class NewObjOp extends Op {
    name() {
        return 'new_obj';
    }
}
exports.NewObjOp = NewObjOp;
/**
 * Operation which creates a new vector object.
 *
 * @category Operations
 */
class NewVecOp extends Op {
    name() {
        return 'new_vec';
    }
}
exports.NewVecOp = NewVecOp;
/**
 * Operation which creates a new string object.
 *
 * @category Operations
 */
class NewStrOp extends Op {
    name() {
        return 'new_str';
    }
}
exports.NewStrOp = NewStrOp;
/**
 * Operation which creates a new binary object.
 *
 * @category Operations
 */
class NewBinOp extends Op {
    name() {
        return 'new_bin';
    }
}
exports.NewBinOp = NewBinOp;
/**
 * Operation which creates a new array object.
 *
 * @category Operations
 */
class NewArrOp extends Op {
    name() {
        return 'new_arr';
    }
}
exports.NewArrOp = NewArrOp;
/**
 * Operation which writes a new value to a value "val" object.
 *
 * @category Operations
 */
class InsValOp extends Op {
    constructor(id, obj, val) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.val = val;
    }
    name() {
        return 'ins_val';
    }
    toString() {
        return super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)}, val = ${(0, clock_1.printTs)(this.val)}`;
    }
}
exports.InsValOp = InsValOp;
/**
 * Operation which sets object keys.
 *
 * @category Operations
 */
class InsObjOp extends Op {
    constructor(id, obj, data) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.data = data;
    }
    name() {
        return 'ins_obj';
    }
    toString(tab = '') {
        const header = super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)}`;
        return (header +
            (0, printTree_1.printTree)(tab, this.data.map((item) => (tab) => `${JSON.stringify(item[0])}: ${(0, clock_1.printTs)(item[1])}`)));
    }
}
exports.InsObjOp = InsObjOp;
/**
 * Operation which sets vector elements.
 *
 * @category Operations
 */
class InsVecOp extends Op {
    constructor(id, obj, data) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.data = data;
    }
    name() {
        return 'ins_vec';
    }
    toString(tab = '') {
        const header = super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)}`;
        return (header +
            (0, printTree_1.printTree)(tab, this.data.map((item) => (tab) => `${item[0]}: ${(0, clock_1.printTs)(item[1])}`)));
    }
}
exports.InsVecOp = InsVecOp;
/**
 * Operation which inserts text into a "str" string object.
 *
 * @category Operations
 */
class InsStrOp extends Op {
    constructor(id, obj, ref, data) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.ref = ref;
        this.data = data;
    }
    span() {
        return this.data.length;
    }
    name() {
        return 'ins_str';
    }
    toString() {
        return super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)} { ${(0, clock_1.printTs)(this.ref)} ← ${JSON.stringify(this.data)} }`;
    }
}
exports.InsStrOp = InsStrOp;
/**
 * Operations which inserts binary data into a "bin" binary object.
 *
 * @category Operations
 */
class InsBinOp extends Op {
    constructor(id, obj, ref, data) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.ref = ref;
        this.data = data;
    }
    span() {
        return this.data.length;
    }
    name() {
        return 'ins_bin';
    }
    toString() {
        const ref = (0, clock_1.printTs)(this.ref);
        return super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)} { ${ref} ← ${this.data} }`;
    }
}
exports.InsBinOp = InsBinOp;
/**
 * Operation which inserts elements into an array.
 *
 * @category Operations
 */
class InsArrOp extends Op {
    /**
     * @param id ID if the first operation in this compound operation.
     * @param obj ID of the array where to insert elements. In theory `arr` is
     *        not necessary as it is possible to find the `arr` just using the
     *        `after` property, however to efficiently be able to find `arr` just
     *        by `after` at runtime all operations would need to be indexed and
     *        also they each would need to store a pointer to array type, which
     *        would require additional dozens of bytes of RAM for each array
     *        insert operation.
     * @param ref ID of the element after which to insert elements.
     * @param data The elements to insert.
     */
    constructor(id, obj, ref, data) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.ref = ref;
        this.data = data;
    }
    span() {
        return this.data.length;
    }
    name() {
        return 'ins_arr';
    }
    toString() {
        const obj = (0, clock_1.printTs)(this.obj);
        const ref = (0, clock_1.printTs)(this.ref);
        const data = this.data.map(clock_1.printTs).join(', ');
        return super.toString() + ', obj = ' + obj + ' { ' + ref + ' ← ' + data + ' }';
    }
}
exports.InsArrOp = InsArrOp;
/**
 * Operation which updates an existing element in an array.
 *
 * @category Operations
 */
class UpdArrOp extends Op {
    /**
     * @param id ID of this operation.
     * @param obj and "arr" object ID where to update an element.
     * @param ref ID of the element to update.
     * @param val ID of the new value to set.
     */
    constructor(id, obj, ref, val) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.ref = ref;
        this.val = val;
    }
    name() {
        return 'upd_arr';
    }
    toString() {
        const obj = (0, clock_1.printTs)(this.obj);
        const ref = (0, clock_1.printTs)(this.ref);
        const val = (0, clock_1.printTs)(this.val);
        return super.toString() + ', obj = ' + obj + ' { ' + ref + ': ' + val + ' }';
    }
}
exports.UpdArrOp = UpdArrOp;
/**
 * Operation which deletes one or more ranges of values in some object.
 * The object could be a string, an array, or a binary.
 *
 * @category Operations
 */
class DelOp extends Op {
    /**
     * @param id ID of this operation.
     * @param obj Object in which to delete something.
     * @param what ID of the first operation to be deleted.
     */
    constructor(id, obj, what) {
        super(id);
        this.id = id;
        this.obj = obj;
        this.what = what;
    }
    name() {
        return 'del';
    }
    toString() {
        const spans = this.what.map((span) => (0, clock_1.printTs)(span) + '!' + span.span).join(', ');
        return super.toString() + `, obj = ${(0, clock_1.printTs)(this.obj)} { ${spans} }`;
    }
}
exports.DelOp = DelOp;
/**
 * Operation which does nothing. Useful for skipping clock cycles, so that
 * operations with a gap in clock can be included in the same patch.
 *
 * @category Operations
 */
class NopOp extends Op {
    constructor(id, len) {
        super(id);
        this.id = id;
        this.len = len;
    }
    span() {
        return this.len;
    }
    name() {
        return 'nop';
    }
}
exports.NopOp = NopOp;
//# sourceMappingURL=operations.js.map