/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { keyAsDetachedField } from "./types.js";
/**
 * Given an {@link UpPath}, checks if it is a path to a detached root.
 */
export function isDetachedUpPathRoot(path) {
    return path.detachedNodeId !== undefined;
}
/**
 * Gets the number of nodes above this one.
 * @remarks
 * Zero when the path's parent is undefined, meaning the path represents a node in a detached field.
 * Runs in O(depth) time.
 */
export function getDepth(path) {
    let depth = 0;
    let next = path.parent;
    while (next !== undefined) {
        depth += 1;
        next = next.parent;
    }
    return depth;
}
export function clonePath(path) {
    if (path === undefined) {
        return undefined;
    }
    return {
        parent: clonePath(path.parent),
        parentField: path.parentField,
        parentIndex: path.parentIndex,
    };
}
/**
 * Gets the elements of the given `path`, ordered from root-most to child-most.
 * @remarks These elements are unchanged and therefore still point "up".
 */
export function topDownPath(path) {
    const out = [];
    let curr = path;
    while (curr !== undefined) {
        out.push(curr);
        curr = curr.parent;
    }
    out.reverse();
    return out;
}
/**
 * Returns true if and only if `a` and `b` describe the same path.
 * @remarks
 * Note that for mutable paths (as used in `AnchorSet`), this equality may change over time: this only checks if the two paths are currently the same.
 */
export function compareUpPaths(a, b) {
    if (a === b) {
        // This handles the both `undefined` case, as well as provides an early out if a shared node is encountered.
        return true;
    }
    if (a === undefined || b === undefined) {
        return false;
    }
    if (a.parentField !== b.parentField || a.parentIndex !== b.parentIndex) {
        return false;
    }
    return compareUpPaths(a.parent, b.parent);
}
/**
 * Returns true if and only if `a` and `b` describe the same field path.
 * @remarks
 * Note that for mutable paths (as used in `AnchorSet`), this equality may change over time: this only checks if the two paths are currently the same.
 */
export function compareFieldUpPaths(a, b) {
    if (a.field !== b.field) {
        return false;
    }
    return compareUpPaths(a.parent, b.parent);
}
/**
 * Checks whether or not a given path is parented under the root field.
 * @param path - the path you want to check.
 * @returns the {@link DetachedField} which contains the path.
 */
export function getDetachedFieldContainingPath(path) {
    let currentPath = path;
    while (currentPath !== undefined) {
        if (currentPath.parent === undefined) {
            return keyAsDetachedField(currentPath.parentField);
        }
        else {
            currentPath = currentPath.parent;
        }
    }
    return keyAsDetachedField(path.parentField);
}
//# sourceMappingURL=pathTree.js.map