/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { idAllocatorFromMaxId } from "../../util/index.js";
import { DetachedFieldIndex } from "./detachedFieldIndex.js";
import { visitDelta } from "./visitDelta.js";
export function makeDetachedFieldIndex(prefix = "Temp", revisionTagCodec, idCompressor, options) {
    return new DetachedFieldIndex(prefix, idAllocatorFromMaxId(), revisionTagCodec, idCompressor, options);
}
export function applyDelta(delta, latestRevision, deltaProcessor, detachedFieldIndex) {
    const visitor = deltaProcessor.acquireVisitor();
    visitDelta(delta, visitor, detachedFieldIndex, latestRevision);
    visitor.free();
}
export function announceDelta(delta, latestRevision, deltaProcessor, detachedFieldIndex) {
    const visitor = deltaProcessor.acquireVisitor();
    visitDelta(delta, combineVisitors([visitor]), detachedFieldIndex, latestRevision);
    visitor.free();
}
/**
 * Combines multiple visitors into a single visitor.
 * @param visitors - The returned visitor invokes the corresponding events for all these visitors, in order.
 * @returns a DeltaVisitor combining all `visitors`.
 */
export function combineVisitors(visitors) {
    const allVisitors = visitors.flatMap((v) => (v.type === "Combined" ? v.visitors : [v]));
    const announcedVisitors = allVisitors.filter((v) => v.type === "Announced");
    return {
        type: "Combined",
        visitors: allVisitors,
        free: () => {
            for (const v of visitors) {
                v.free();
            }
        },
        create: (...args) => {
            for (const v of allVisitors) {
                v.create(...args);
            }
            for (const v of announcedVisitors) {
                v.afterCreate(...args);
            }
        },
        destroy: (...args) => {
            for (const v of announcedVisitors) {
                v.beforeDestroy(...args);
            }
            for (const v of allVisitors) {
                v.destroy(...args);
            }
        },
        attach: (source, count, destination) => {
            for (const v of announcedVisitors) {
                v.beforeAttach(source, count, destination);
            }
            for (const v of allVisitors) {
                v.attach(source, count, destination);
            }
            for (const v of announcedVisitors) {
                v.afterAttach(source, {
                    start: destination,
                    end: destination + count,
                });
            }
        },
        detach: (source, destination, id, isReplaced) => {
            for (const v of announcedVisitors) {
                v.beforeDetach(source, destination, isReplaced);
            }
            for (const v of allVisitors) {
                v.detach(source, destination, id, isReplaced);
            }
            for (const v of announcedVisitors) {
                v.afterDetach(source.start, source.end - source.start, destination, isReplaced);
            }
        },
        enterNode: (...args) => {
            for (const v of allVisitors) {
                v.enterNode(...args);
            }
        },
        exitNode: (...args) => {
            for (const v of allVisitors) {
                v.exitNode(...args);
            }
        },
        enterField: (...args) => {
            for (const v of allVisitors) {
                v.enterField(...args);
            }
        },
        exitField: (...args) => {
            for (const v of allVisitors) {
                v.exitField(...args);
            }
        },
        fieldMarks: (marks) => {
            for (const v of allVisitors) {
                v.fieldMarks?.(marks);
            }
        },
    };
}
const noOp = () => { };
/**
 * Creates an announced visitor with only the provided functions and uses a no op for the rest.
 * This is provided to make some of the delta visitor definitions cleaner.
 */
export function createAnnouncedVisitor(visitorFunctions) {
    return {
        type: "Announced",
        free: visitorFunctions.free ?? noOp,
        create: visitorFunctions.create ?? noOp,
        afterCreate: visitorFunctions.afterCreate ?? noOp,
        beforeDestroy: visitorFunctions.beforeDestroy ?? noOp,
        destroy: visitorFunctions.destroy ?? noOp,
        beforeAttach: visitorFunctions.beforeAttach ?? noOp,
        attach: visitorFunctions.attach ?? noOp,
        afterAttach: visitorFunctions.afterAttach ?? noOp,
        beforeDetach: visitorFunctions.beforeDetach ?? noOp,
        detach: visitorFunctions.detach ?? noOp,
        afterDetach: visitorFunctions.afterDetach ?? noOp,
        enterNode: visitorFunctions.enterNode ?? noOp,
        exitNode: visitorFunctions.exitNode ?? noOp,
        enterField: visitorFunctions.enterField ?? noOp,
        exitField: visitorFunctions.exitField ?? noOp,
    };
}
//# sourceMappingURL=visitorUtils.js.map