"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocationBasedDataEditor = void 0;
const internal_1 = require("@fluidframework/telemetry-utils/internal");
const index_js_1 = require("../../core/index.js");
/**
 * Implementation of {@link DataEditor} based on the default set of supported field kinds.
 * @sealed
 */
class LocationBasedDataEditor {
    constructor(idBasedEditor, locator) {
        this.idBasedEditor = idBasedEditor;
        this.locator = locator;
    }
    addNodeExistsConstraint(path) {
        const normal = normalizeUpPath(path, this.locator);
        this.idBasedEditor.addNodeExistsConstraint(normal);
    }
    addNodeExistsConstraintOnRevert(path) {
        const normal = normalizeUpPath(path, this.locator);
        this.idBasedEditor.addNodeExistsConstraintOnRevert(normal);
    }
    buildRoots(content) {
        const roots = this.idBasedEditor.buildRoots(content);
        const locations = this.locator.locationsFromIdRanges(roots);
        return locations;
    }
    valueField(field) {
        const normal = normalizeFieldUpPath(field, this.locator);
        const lowLevelEditor = this.idBasedEditor.valueField(normal);
        const locator = this.locator;
        const editBuilder = {
            set: (newContent) => {
                lowLevelEditor.set(newContent);
            },
            attach: (newContent) => {
                const changeAtom = locator.idFromLocation(newContent);
                lowLevelEditor.attach(changeAtom);
            },
        };
        return editBuilder;
    }
    optionalField(field) {
        const normal = normalizeFieldUpPath(field, this.locator);
        const lowLevelEditor = this.idBasedEditor.optionalField(normal);
        const locator = this.locator;
        const editBuilder = {
            set: (newContent, wasEmpty) => {
                lowLevelEditor.set(newContent, wasEmpty);
            },
            attach: (newContent, wasEmpty) => {
                if (newContent === undefined) {
                    editBuilder.clear(wasEmpty);
                    return;
                }
                const changeAtom = locator.idFromLocation(newContent);
                lowLevelEditor.attach(changeAtom, wasEmpty);
            },
            clear: (wasEmpty) => {
                lowLevelEditor.clear(wasEmpty);
            },
        };
        return editBuilder;
    }
    move(sourceField, sourceIndex, count, destinationField, destIndex) {
        const normalSource = normalizeFieldUpPath(sourceField, this.locator);
        const normalDestination = normalizeFieldUpPath(destinationField, this.locator);
        this.idBasedEditor.move(normalSource, sourceIndex, count, normalDestination, destIndex);
    }
    sequenceField(field) {
        const normal = normalizeFieldUpPath(field, this.locator);
        const lowLevelEditor = this.idBasedEditor.sequenceField(normal);
        const locator = this.locator;
        const editBuilder = {
            insert: (index, content) => {
                lowLevelEditor.insert(index, content);
            },
            attach: (index, newContent) => {
                const range = locator.idRangesFromLocations(newContent);
                lowLevelEditor.attach(index, range);
            },
            remove: (index, count) => {
                lowLevelEditor.remove(index, count);
            },
        };
        return editBuilder;
    }
}
exports.LocationBasedDataEditor = LocationBasedDataEditor;
function normalizeUpPath(path, locator) {
    if (path.parent === undefined) {
        if (path.parentField === index_js_1.rootFieldKey) {
            return { ...path, parent: undefined, detachedNodeId: undefined };
        }
        else {
            const nodeId = locator.idFromLocation(path.parentField);
            const detachedNodeId = (0, index_js_1.makeDetachedNodeId)(nodeId.revision, nodeId.localId);
            return { ...path, parent: undefined, detachedNodeId };
        }
    }
    else {
        return {
            parent: normalizeUpPath(path.parent, locator),
            parentField: path.parentField,
            parentIndex: path.parentIndex,
        };
    }
}
function normalizeFieldUpPath(path, locator) {
    if (path.parent === undefined) {
        if (path.field === index_js_1.rootFieldKey) {
            return { parent: undefined, field: index_js_1.rootFieldKey };
        }
        else {
            throw new internal_1.UsageError("Editing only allowed on the root field or on fields under nodes with TreeStatus.InDocument or TreeStatus.Removed status");
        }
    }
    else {
        return { parent: normalizeUpPath(path.parent, locator), field: path.field };
    }
}
//# sourceMappingURL=locationBasedEditBuilder.js.map