"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GeneralWriteTimeIVStore = exports.DelayDeltaValue = exports.WriteTimeIVCollector = exports.WriteTimeIVDBlossomAllocator = exports.WriteTimeIVDBlossom = exports.WriteTimeIVDAllocator = exports.WriteTimeIVD = exports.CReadTimeIVS = exports.ReadTimeIVD = void 0;
const ImpLib = require("@ot-builder/common-impl");
const errors_1 = require("@ot-builder/errors");
const value_collector_1 = require("../common/value-collector");
class ReadTimeIVD {
    constructor(cr) {
        this.masterIDs = [];
        this.deltas = [];
        this.valueCreator = cr;
    }
}
exports.ReadTimeIVD = ReadTimeIVD;
class CReadTimeIVS {
    constructor(monoidX) {
        this.monoidX = monoidX;
        this.knownMasters = [];
        this.itemVariationData = [];
    }
    tryGetIVD(outer) {
        return this.itemVariationData[outer] || null;
    }
    getIVD(outer) {
        if (!this.itemVariationData[outer])
            throw errors_1.Errors.Variation.IndexOverflow("outer", outer);
        return this.itemVariationData[outer];
    }
    getMaster(id) {
        const master = this.knownMasters[id];
        if (!master)
            throw errors_1.Errors.Variation.IndexOverflow(`master`, id);
        return master;
    }
    buildValue(ivd, deltas) {
        const variance = [];
        for (let mu = 0; mu < deltas.length; mu++) {
            variance.push([this.getMaster(ivd.masterIDs[mu]), deltas[mu]]);
        }
        return ivd.valueCreator.create(0, variance);
    }
    queryValue(outer, inner) {
        if (outer === 0xffff && inner === 0xffff)
            return this.monoidX.neutral;
        const ivd = this.getIVD(outer);
        return this.buildValue(ivd, ivd.deltas[inner]);
    }
}
exports.CReadTimeIVS = CReadTimeIVS;
class WriteTimeIVD {
    constructor(long, arity, outerIndex, masterIDs) {
        this.long = long;
        this.arity = arity;
        this.outerIndex = outerIndex;
        this.masterIDs = masterIDs;
        this.allocator = new ImpLib.IndexAllocator();
        this.mapping = new ImpLib.PathMapImpl(); // Path length = arity * mIDs.length
    }
    enter(deltas) {
        const lens = this.mapping.createLens();
        lens.focus(deltas);
        return lens.getOrAlloc(this.allocator) * this.arity;
    }
    *entries() {
        for (const [deltaRowEntire, innerIDRaw] of this.mapping.entries()) {
            for (let m = 0; m < this.arity; m++) {
                yield [
                    deltaRowEntire.slice(this.masterIDs.length * m, this.masterIDs.length * (m + 1)),
                    innerIDRaw * this.arity + m
                ];
            }
        }
    }
    get size() {
        return this.allocator.count * this.arity;
    }
}
exports.WriteTimeIVD = WriteTimeIVD;
class WriteTimeIVDAllocator {
    constructor() {
        this.allocOuterID = new ImpLib.IndexAllocator();
        this.ivdList = [];
    }
    next(fLong, arity, r) {
        const outerID = this.allocOuterID.next();
        const ivd = new WriteTimeIVD(fLong, arity, outerID, r);
        this.ivdList[outerID] = ivd;
        return ivd;
    }
    *entries() {
        yield* this.ivdList;
    }
    isEmpty() {
        return !this.ivdList || !this.ivdList.length;
    }
}
exports.WriteTimeIVDAllocator = WriteTimeIVDAllocator;
class WriteTimeIVDBlossom {
    constructor(nodeAlloc, maxInnerIndex, masterIDs) {
        this.nodeAlloc = nodeAlloc;
        this.maxInnerIndex = maxInnerIndex;
        this.masterIDs = masterIDs;
        this.ivdListShort = [];
        this.ivdListLong = [];
    }
    getFreeIVD(fLong, arity) {
        const ivdListCollection = fLong ? this.ivdListLong : this.ivdListShort;
        let ivdList = ivdListCollection[arity];
        if (!ivdList) {
            ivdList = [];
            ivdListCollection[arity] = ivdList;
        }
        if (!ivdList.length || ivdList[ivdList.length - 1].size >= this.maxInnerIndex) {
            const ivd = this.nodeAlloc.next(fLong, arity, this.masterIDs);
            ivdList.push(ivd);
            return ivd;
        }
        else {
            return ivdList[ivdList.length - 1];
        }
    }
}
exports.WriteTimeIVDBlossom = WriteTimeIVDBlossom;
class WriteTimeIVDBlossomAllocator {
    constructor(nodeAlloc, maxInnerIndex) {
        this.nodeAlloc = nodeAlloc;
        this.maxInnerIndex = maxInnerIndex;
    }
    next(masterIDs) {
        return new WriteTimeIVDBlossom(this.nodeAlloc, this.maxInnerIndex, masterIDs);
    }
}
exports.WriteTimeIVDBlossomAllocator = WriteTimeIVDBlossomAllocator;
class WriteTimeIVCollector extends value_collector_1.DelayValueCollector {
    constructor(op, masterSet, pmBlossom, acBlossom) {
        super(op, masterSet);
        this.pmBlossom = pmBlossom;
        this.acBlossom = acBlossom;
    }
    createCollectedValue(origin, deltaMA) {
        return new DelayDeltaValue(this, origin, deltaMA);
    }
    getIVD(fLong, arity) {
        this.settleDown();
        if (!this.relocation.length)
            return null;
        const lens = this.pmBlossom.createLens();
        lens.focus(this.relocation);
        const blossom = lens.getOrAlloc(this.acBlossom, this.relocation);
        return blossom.getFreeIVD(fLong, arity);
    }
    forceGetIVD(fLong, arity, master) {
        this.settleDown();
        if (!this.relocation.length) {
            this.addMaster(master);
            this.settleDown();
        }
        const lens = this.pmBlossom.createLens();
        lens.focus(this.relocation);
        const blossom = lens.getOrAlloc(this.acBlossom, this.relocation);
        return blossom.getFreeIVD(fLong, arity);
    }
}
exports.WriteTimeIVCollector = WriteTimeIVCollector;
class DelayDeltaValue {
    constructor(col, origin, deltaMA) {
        this.col = col;
        this.origin = origin;
        this.deltaMA = deltaMA;
    }
    resolve() {
        return this.col.resolveDeltas(this.deltaMA);
    }
}
exports.DelayDeltaValue = DelayDeltaValue;
class GeneralWriteTimeIVStore {
    constructor(op, masterCollector, maxInnerIndex) {
        this.op = op;
        this.masterCollector = masterCollector;
        this.maxInnerIndex = maxInnerIndex;
        this.pmBlossom = new ImpLib.PathMapImpl();
        this.acIVD = new WriteTimeIVDAllocator();
        this.acBlossom = new WriteTimeIVDBlossomAllocator(this.acIVD, this.maxInnerIndex);
    }
    createCollector() {
        return new WriteTimeIVCollector(this.op, this.masterCollector, this.pmBlossom, this.acBlossom);
    }
    valueToInnerOuterIDImpl(fLong, xs) {
        const collector = this.createCollector();
        const dvs = [];
        for (const item of xs)
            dvs.push(collector.collect(item));
        const ivd = collector.getIVD(fLong, dvs.length);
        if (!ivd)
            return null;
        const deltas = [];
        for (const dv of dvs) {
            for (const delta of dv.resolve())
                deltas.push(delta);
        }
        const innerIndex = ivd.enter(deltas);
        return { outer: ivd.outerIndex, inner: innerIndex };
    }
    valueToInnerOuterIDForceImpl(fLong, xs, fallbackMaster) {
        const collector = this.createCollector();
        const dvs = [];
        for (const item of xs)
            dvs.push(collector.collect(item));
        let ivd = collector.getIVD(fLong, dvs.length);
        if (!ivd)
            ivd = collector.forceGetIVD(fLong, dvs.length, fallbackMaster);
        const deltas = [];
        for (const dv of dvs) {
            for (const delta of dv.resolve())
                deltas.push(delta);
        }
        const innerIndex = ivd.enter(deltas);
        return { outer: ivd.outerIndex, inner: innerIndex };
    }
    // Target data type being short
    valueToInnerOuterID(x) {
        return this.valueToInnerOuterIDImpl(false, [x]);
    }
    valueToInnerOuterIDForce(x, fallbackMaster) {
        return this.valueToInnerOuterIDForceImpl(false, [x], fallbackMaster);
    }
    multiValueToInnerOuterID(xs) {
        return this.valueToInnerOuterIDImpl(false, xs);
    }
    multiValueToInnerOuterIDForce(xs, fallbackMaster) {
        return this.valueToInnerOuterIDForceImpl(false, xs, fallbackMaster);
    }
    // Target data type being long
    longValueToInnerOuterID(x) {
        return this.valueToInnerOuterIDImpl(true, [x]);
    }
    longValueToInnerOuterIDForce(x, fallbackMaster) {
        return this.valueToInnerOuterIDForceImpl(true, [x], fallbackMaster);
    }
    multiLongValueToInnerOuterID(xs) {
        return this.valueToInnerOuterIDImpl(true, xs);
    }
    multiLongValueToInnerOuterIDForce(xs, fallbackMaster) {
        return this.valueToInnerOuterIDForceImpl(true, xs, fallbackMaster);
    }
    isEmpty() {
        return this.masterCollector.size === 0 || this.acIVD.isEmpty();
    }
    *masters() {
        yield* this.masterCollector;
    }
    ivdList() {
        return this.acIVD.entries();
    }
}
exports.GeneralWriteTimeIVStore = GeneralWriteTimeIVStore;
//# sourceMappingURL=general.js.map