/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { assert, unreachableCase } from "@fluidframework/core-utils";
import { CrossFieldTarget } from "../modular-schema/index.js";
import { brand } from "../../util/index.js";
import { isAttachAndDetachEffect, splitMark, splitMarkEffect } from "./utils.js";
export var MoveEnd;
(function (MoveEnd) {
    MoveEnd[MoveEnd["Source"] = 0] = "Source";
    MoveEnd[MoveEnd["Dest"] = 1] = "Dest";
})(MoveEnd || (MoveEnd = {}));
export function setMoveEffect(moveEffects, target, revision, id, count, effect, invalidate = true) {
    effect.basis = id;
    moveEffects.set(target, revision, id, count, effect, invalidate);
}
export function getMoveEffect(moveEffects, target, revision, id, count, addDependency = true) {
    const result = moveEffects.get(target, revision, id, count, addDependency);
    return result.value !== undefined
        ? { ...result, value: adjustMoveEffectBasis(result.value, id) }
        : result;
}
export function isMoveMark(effect) {
    return isMoveOut(effect) || isMoveIn(effect);
}
export function isMoveOut(effect) {
    return effect.type === "MoveOut";
}
export function isMoveIn(effect) {
    return effect.type === "MoveIn";
}
export function getMoveIn(effect) {
    switch (effect.type) {
        case "MoveIn":
            return effect;
        case "AttachAndDetach":
            return getMoveIn(effect.attach);
        default:
            return undefined;
    }
}
function adjustMoveEffectBasis(effect, newBasis) {
    if (effect.basis === newBasis) {
        return effect;
    }
    const adjusted = { ...effect, basis: newBasis };
    const basisShift = newBasis - effect.basis;
    assert(basisShift > 0, 0x812 /* Expected basis shift to be positive */);
    if (effect.endpoint !== undefined) {
        adjusted.endpoint = {
            ...effect.endpoint,
            localId: brand(effect.endpoint.localId + basisShift),
        };
    }
    if (effect.movedEffect !== undefined) {
        const [_mark1, mark2] = splitMarkEffect(effect.movedEffect, basisShift);
        adjusted.movedEffect = mark2;
    }
    return adjusted;
}
export function splitMarkForMoveEffects(mark, revision, effects) {
    const length = getFirstMoveEffectLength(mark, mark.count, revision, effects);
    return length < mark.count ? splitMark(mark, length) : [mark];
}
function getFirstMoveEffectLength(markEffect, count, revision, effects) {
    if (isMoveMark(markEffect)) {
        return getMoveEffect(effects, getCrossFieldTargetFromMove(markEffect), markEffect.revision ?? revision, markEffect.id, count).length;
    }
    else if (isAttachAndDetachEffect(markEffect)) {
        return Math.min(getFirstMoveEffectLength(markEffect.attach, count, revision, effects), getFirstMoveEffectLength(markEffect.detach, count, revision, effects));
    }
    return count;
}
export function getCrossFieldTargetFromMove(mark) {
    const type = mark.type;
    switch (type) {
        case "MoveIn":
            return CrossFieldTarget.Destination;
        case "MoveOut":
            return CrossFieldTarget.Source;
        default:
            unreachableCase(type);
    }
}
//# sourceMappingURL=moveEffectTable.js.map