"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRefCount = exports.validatePartialLengths = exports.countOperations = exports.nodeOrdinalsHaveIntegrity = exports.markRangeRemoved = exports.insertSegments = exports.insertText = exports.insertMarker = exports.loadTextFromFileWithMarkers = exports.loadTextFromFile = void 0;
const assert_1 = require("assert");
const fs_1 = __importDefault(require("fs"));
const mergeTreeNodes_1 = require("../mergeTreeNodes.cjs");
const textSegment_1 = require("../textSegment.cjs");
const mergeTreeNodeWalk_1 = require("../mergeTreeNodeWalk.cjs");
const constants_1 = require("../constants.cjs");
const text_1 = require("./text.cjs");
function loadTextFromFile(filename, mergeTree, segLimit = 0) {
    const content = fs_1.default.readFileSync(filename, "utf8");
    return (0, text_1.loadText)(content, mergeTree, segLimit);
}
exports.loadTextFromFile = loadTextFromFile;
function loadTextFromFileWithMarkers(filename, mergeTree, segLimit = 0) {
    const content = fs_1.default.readFileSync(filename, "utf8");
    return (0, text_1.loadText)(content, mergeTree, segLimit, true);
}
exports.loadTextFromFileWithMarkers = loadTextFromFileWithMarkers;
function insertMarker({ mergeTree, pos, refSeq, clientId, seq, behaviors, props, opArgs, }) {
    mergeTree.insertSegments(pos, [mergeTreeNodes_1.Marker.make(behaviors, props)], refSeq, clientId, seq, opArgs);
}
exports.insertMarker = insertMarker;
function insertText({ mergeTree, pos, refSeq, clientId, seq, text, props, opArgs, }) {
    mergeTree.insertSegments(pos, [textSegment_1.TextSegment.make(text, props)], refSeq, clientId, seq, opArgs);
}
exports.insertText = insertText;
function insertSegments({ mergeTree, pos, segments, refSeq, clientId, seq, opArgs, }) {
    mergeTree.insertSegments(pos, segments, refSeq, clientId, seq, opArgs);
}
exports.insertSegments = insertSegments;
function markRangeRemoved({ mergeTree, start, end, refSeq, clientId, seq, overwrite = false, opArgs, }) {
    mergeTree.markRangeRemoved(start, end, refSeq, clientId, seq, overwrite, opArgs);
}
exports.markRangeRemoved = markRangeRemoved;
function nodeOrdinalsHaveIntegrity(block) {
    const olen = block.ordinal.length;
    for (let i = 0; i < block.childCount; i++) {
        if (block.children[i].ordinal) {
            if (olen !== block.children[i].ordinal.length - 1) {
                console.log("node integrity issue");
                return false;
            }
            if (i > 0) {
                if (block.children[i].ordinal <= block.children[i - 1].ordinal) {
                    console.log("node sib integrity issue");
                    return false;
                }
            }
            if (!block.children[i].isLeaf()) {
                return nodeOrdinalsHaveIntegrity(block.children[i]);
            }
        }
        else {
            console.log(`node child ordinal not set ${i}`);
            return false;
        }
    }
    return true;
}
exports.nodeOrdinalsHaveIntegrity = nodeOrdinalsHaveIntegrity;
/**
 * Returns an object that tallies each delta and maintenance operation observed
 * for the given 'mergeTree'.
 */
function countOperations(mergeTree) {
    const counts = {};
    assert_1.strict.strictEqual(mergeTree.mergeTreeDeltaCallback, undefined);
    assert_1.strict.strictEqual(mergeTree.mergeTreeMaintenanceCallback, undefined);
    const fn = (deltaArgs) => {
        const previous = counts[deltaArgs.operation];
        counts[deltaArgs.operation] = previous === undefined ? 1 : previous + 1;
    };
    mergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs) => {
        fn(deltaArgs);
    };
    mergeTree.mergeTreeMaintenanceCallback = fn;
    return counts;
}
exports.countOperations = countOperations;
function getPartialLengths(clientId, seq, mergeTree, localSeq, mergeBlock = mergeTree.root) {
    const partialLen = mergeBlock.partialLengths?.getPartialLength(seq, clientId, localSeq);
    let actualLen = 0;
    const isInserted = (segment) => segment.seq === undefined ||
        (segment.seq !== constants_1.UnassignedSequenceNumber && segment.seq <= seq) ||
        (localSeq !== undefined &&
            segment.seq === constants_1.UnassignedSequenceNumber &&
            segment.localSeq !== undefined &&
            segment.localSeq <= localSeq);
    const isRemoved = (segment) => segment.removedSeq !== undefined &&
        ((localSeq !== undefined &&
            segment.removedSeq === constants_1.UnassignedSequenceNumber &&
            segment.localRemovedSeq !== undefined &&
            segment.localRemovedSeq <= localSeq) ||
            (segment.removedSeq !== constants_1.UnassignedSequenceNumber && segment.removedSeq <= seq));
    const isMoved = (segment) => segment.movedSeq !== undefined &&
        ((localSeq !== undefined &&
            segment.movedSeq === constants_1.UnassignedSequenceNumber &&
            segment.localMovedSeq !== undefined &&
            segment.localMovedSeq <= localSeq) ||
            (segment.movedSeq !== constants_1.UnassignedSequenceNumber && segment.movedSeq <= seq));
    (0, mergeTreeNodeWalk_1.walkAllChildSegments)(mergeBlock, (segment) => {
        if (isInserted(segment) && !isRemoved(segment) && !isMoved(segment)) {
            actualLen += segment.cachedLength;
        }
        return true;
    });
    return {
        partialLen,
        actualLen,
    };
}
function validatePartialLengths(clientId, mergeTree, expectedValues, localSeq, mergeBlock = mergeTree.root) {
    mergeTree.computeLocalPartials(0);
    for (let i = mergeTree.collabWindow.minSeq + 1; i <= mergeTree.collabWindow.currentSeq; i++) {
        const { partialLen, actualLen } = getPartialLengths(clientId, i, mergeTree, localSeq, mergeBlock);
        if (partialLen && partialLen < 0) {
            assert_1.strict.fail("Negative partial length returned");
        }
        assert_1.strict.equal(partialLen, actualLen);
    }
    if (!expectedValues) {
        return;
    }
    for (const { seq, len, localSeq: expectedLocalSeq } of expectedValues) {
        const { partialLen, actualLen } = getPartialLengths(clientId, seq, mergeTree, expectedLocalSeq ?? localSeq, mergeBlock);
        assert_1.strict.equal(partialLen, len);
        assert_1.strict.equal(actualLen, len);
    }
}
exports.validatePartialLengths = validatePartialLengths;
function validateRefCount(collection) {
    if (!collection) {
        return;
    }
    const expectedLength = Array.from(collection).length;
    // eslint-disable-next-line @typescript-eslint/dot-notation
    assert_1.strict.equal(collection["refCount"], expectedLength);
}
exports.validateRefCount = validateRefCount;
//# sourceMappingURL=testUtils.cjs.map