/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { Type } from "@sinclair/typebox";
import { RangeMap, brand, brandedNumberType, brandedStringType, } from "../../util/index.js";
/**
 * The identifier for a particular session/user/client that can generate `GraphCommit`s
 */
export const SessionIdSchema = brandedStringType();
export const RevisionTagSchema = Type.Union([
    Type.Literal("root"),
    brandedNumberType(),
]);
/**
 * Returns true iff `a` and `b` are the same.
 */
export function areEqualChangeAtomIds(a, b) {
    return a.localId === b.localId && a.revision === b.revision;
}
export function areEqualChangeAtomIdOpts(a, b) {
    if (a === undefined || b === undefined) {
        return a === b;
    }
    return areEqualChangeAtomIds(a, b);
}
/**
 * Returns a ChangeAtomId with the given revision and local ID.
 */
export function makeChangeAtomId(localId, revision) {
    return revision === undefined ? { localId } : { localId, revision };
}
export function asChangeAtomId(id) {
    return typeof id === "object" ? id : { localId: id };
}
export function taggedAtomId(id, revision) {
    return makeChangeAtomId(id.localId, id.revision ?? revision);
}
export function taggedOptAtomId(id, revision) {
    if (id === undefined) {
        return undefined;
    }
    return taggedAtomId(id, revision);
}
export function offsetChangeAtomId(id, offset) {
    return { ...id, localId: brand(id.localId + offset) };
}
export function replaceAtomRevisions(id, oldRevisions, newRevision) {
    return oldRevisions.has(id.revision) ? atomWithRevision(id, newRevision) : id;
}
function atomWithRevision(id, revision) {
    const updated = { ...id, revision };
    if (revision === undefined) {
        delete updated.revision;
    }
    return updated;
}
/**
 * The type of a commit. This is used to describe the context in which the commit was created.
 *
 * @public
 */
export var CommitKind;
(function (CommitKind) {
    /** A commit corresponding to a change that is not the result of an undo/redo from this client. */
    CommitKind[CommitKind["Default"] = 0] = "Default";
    /** A commit that is the result of an undo from this client. */
    CommitKind[CommitKind["Undo"] = 1] = "Undo";
    /** A commit that is the result of a redo from this client. */
    CommitKind[CommitKind["Redo"] = 2] = "Redo";
})(CommitKind || (CommitKind = {}));
/**
 * Creates a new graph commit object. This is useful for creating copies of commits with different parentage.
 * @param parent - the parent of the new commit
 * @param commit - the contents of the new commit object
 * @returns the new commit object
 */
// Note that this function is synchronous, and therefore it is not a Promise.
// However, it is still a strong commit-mint.
export function mintCommit(parent, commit) {
    const { revision, change } = commit;
    return {
        revision,
        change,
        parent,
    };
}
export function newChangeAtomIdRangeMap() {
    return new RangeMap(offsetChangeAtomId, subtractChangeAtomIds);
}
export function subtractChangeAtomIds(a, b) {
    const cmp = compareRevisions(a.revision, b.revision);
    if (cmp !== 0) {
        return cmp * Number.POSITIVE_INFINITY;
    }
    return a.localId - b.localId;
}
export function compareRevisions(a, b) {
    if (a === undefined) {
        return b === undefined ? 0 : -1;
    }
    else if (b === undefined) {
        return 1;
    }
    else if (a < b) {
        return -1;
    }
    else if (a > b) {
        return 1;
    }
    return 0;
}
//# sourceMappingURL=types.js.map