"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.combineVisitors = exports.announceDelta = exports.applyDelta = exports.makeDetachedFieldIndex = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../util/index.js");
const detachedFieldIndex_js_1 = require("./detachedFieldIndex.js");
const visitDelta_js_1 = require("./visitDelta.js");
function makeDetachedFieldIndex(prefix = "Temp", revisionTagCodec, idCompressor, options) {
    return new detachedFieldIndex_js_1.DetachedFieldIndex(prefix, (0, index_js_1.idAllocatorFromMaxId)(), revisionTagCodec, idCompressor, options);
}
exports.makeDetachedFieldIndex = makeDetachedFieldIndex;
function applyDelta(delta, deltaProcessor, detachedFieldIndex) {
    const visitor = deltaProcessor.acquireVisitor();
    (0, visitDelta_js_1.visitDelta)(delta, visitor, detachedFieldIndex);
    visitor.free();
}
exports.applyDelta = applyDelta;
function announceDelta(delta, deltaProcessor, detachedFieldIndex) {
    const visitor = deltaProcessor.acquireVisitor();
    (0, visitDelta_js_1.visitDelta)(delta, combineVisitors([visitor], [visitor]), detachedFieldIndex);
    visitor.free();
}
exports.announceDelta = announceDelta;
/**
 * @param visitors - The returned visitor invokes the corresponding events for all these visitors, in order.
 * @param announcedVisitors - Subset of `visitors` to also call {@link AnnouncedVisitor} methods on.
 * This must be a subset of `visitors`: if not the visitor will not have its path correctly set when the events are triggered.
 * When `visitors` are making changes to data, `announcedVisitors` can be used to get extra events before or after all the changes from all the visitors have been made.
 * This can, for example, enable visitors to have access to the tree in these extra events despite multiple separate visitors updating different tree related data-structures.
 * @returns a DeltaVisitor combining all `visitors`.
 */
function combineVisitors(visitors, announcedVisitors = []) {
    {
        const set = new Set(visitors);
        for (const item of announcedVisitors) {
            (0, internal_1.assert)(set.has(item), 0x8c8 /* AnnouncedVisitor would not get traversed */);
        }
    }
    return {
        free: () => visitors.forEach((v) => v.free()),
        create: (...args) => {
            visitors.forEach((v) => v.create(...args));
            announcedVisitors.forEach((v) => v.afterCreate(...args));
        },
        destroy: (...args) => {
            announcedVisitors.forEach((v) => v.beforeDestroy(...args));
            visitors.forEach((v) => v.destroy(...args));
        },
        attach: (source, count, destination) => {
            announcedVisitors.forEach((v) => v.beforeAttach(source, count, destination));
            visitors.forEach((v) => v.attach(source, count, destination));
            announcedVisitors.forEach((v) => v.afterAttach(source, { start: destination, end: destination + count }));
        },
        detach: (source, destination) => {
            announcedVisitors.forEach((v) => v.beforeDetach(source, destination));
            visitors.forEach((v) => v.detach(source, destination));
            announcedVisitors.forEach((v) => v.afterDetach(source.start, source.end - source.start, destination));
        },
        replace: (newContent, oldContent, oldContentDestination) => {
            announcedVisitors.forEach((v) => v.beforeReplace(newContent, oldContent, oldContentDestination));
            visitors.forEach((v) => v.replace(newContent, oldContent, oldContentDestination));
            announcedVisitors.forEach((v) => v.afterReplace(newContent, oldContent, oldContentDestination));
        },
        enterNode: (...args) => visitors.forEach((v) => v.enterNode(...args)),
        exitNode: (...args) => visitors.forEach((v) => v.exitNode(...args)),
        enterField: (...args) => visitors.forEach((v) => v.enterField(...args)),
        exitField: (...args) => visitors.forEach((v) => v.exitField(...args)),
    };
}
exports.combineVisitors = combineVisitors;
//# sourceMappingURL=visitorUtils.js.map