"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SegmentPropertiesManager = void 0;
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const common_utils_1 = require("@fluidframework/common-utils");
const constants_1 = require("./constants");
const Properties = __importStar(require("./properties"));
class SegmentPropertiesManager {
    constructor(segment) {
        this.segment = segment;
        this.pendingRewriteCount = 0;
    }
    ackPendingProperties(annotateOp) {
        var _a, _b;
        if (annotateOp.combiningOp && annotateOp.combiningOp.name === "rewrite") {
            this.pendingRewriteCount--;
        }
        for (const key of Object.keys(annotateOp.props)) {
            if (((_a = this.pendingKeyUpdateCount) === null || _a === void 0 ? void 0 : _a[key]) !== undefined) {
                common_utils_1.assert(this.pendingKeyUpdateCount[key] > 0, 0x05c /* "Trying to update more annotate props than do exist!" */);
                this.pendingKeyUpdateCount[key]--;
                if (((_b = this.pendingKeyUpdateCount) === null || _b === void 0 ? void 0 : _b[key]) === 0) {
                    // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
                    delete this.pendingKeyUpdateCount[key];
                }
            }
        }
    }
    addProperties(newProps, op, seq, collabWindow) {
        var _a;
        if (!this.segment.properties) {
            this.segment.properties = Properties.createMap();
            this.pendingKeyUpdateCount = Properties.createMap();
        }
        const collaborating = collabWindow && collabWindow.collaborating;
        // There are outstanding local rewrites, so block all non-local changes
        if (this.pendingRewriteCount > 0 && seq !== constants_1.UnassignedSequenceNumber && collaborating) {
            return undefined;
        }
        const rewrite = (op && op.name === "rewrite");
        const combiningOp = !rewrite ? op ? op : undefined : undefined;
        const shouldModifyKey = (key) => {
            var _a;
            if (seq === constants_1.UnassignedSequenceNumber
                || ((_a = this.pendingKeyUpdateCount) === null || _a === void 0 ? void 0 : _a[key]) === undefined
                || combiningOp) {
                return true;
            }
            return false;
        };
        const deltas = {};
        if (rewrite) {
            if (collaborating && seq === constants_1.UnassignedSequenceNumber) {
                this.pendingRewriteCount++;
            }
            // We are re-writting so delete all the properties
            // not in the new props
            for (const key of Object.keys(this.segment.properties)) {
                if (!newProps[key] && shouldModifyKey(key)) {
                    deltas[key] = this.segment.properties[key];
                    // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
                    delete this.segment.properties[key];
                }
            }
        }
        for (const key of Object.keys(newProps)) {
            if (collaborating) {
                if (seq === constants_1.UnassignedSequenceNumber) {
                    if (((_a = this.pendingKeyUpdateCount) === null || _a === void 0 ? void 0 : _a[key]) === undefined) {
                        this.pendingKeyUpdateCount[key] = 0;
                    }
                    this.pendingKeyUpdateCount[key]++;
                }
                else if (!shouldModifyKey(key)) {
                    continue;
                }
            }
            const previousValue = this.segment.properties[key];
            // The delta should be null if undefined, as thats how we encode delete
            deltas[key] = (previousValue === undefined) ? null : previousValue;
            let newValue;
            if (combiningOp) {
                newValue = Properties.combine(combiningOp, previousValue, newValue, seq);
            }
            else {
                newValue = newProps[key];
            }
            if (newValue === null) {
                // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
                delete this.segment.properties[key];
            }
            else {
                this.segment.properties[key] = newValue;
            }
        }
        return deltas;
    }
    copyTo(leafSegment) {
        if (this.segment.properties) {
            leafSegment.properties = Properties.createMap();
            for (const key of Object.keys(this.segment.properties)) {
                leafSegment.properties[key] = this.segment.properties[key];
            }
            if (this.segment.propertyManager) {
                leafSegment.propertyManager = new SegmentPropertiesManager(leafSegment);
                leafSegment.propertyManager.pendingRewriteCount = this.pendingRewriteCount;
                leafSegment.propertyManager.pendingKeyUpdateCount = Properties.createMap();
                for (const key of Object.keys(this.pendingKeyUpdateCount)) {
                    leafSegment.propertyManager.pendingKeyUpdateCount[key] = this.pendingKeyUpdateCount[key];
                }
            }
        }
    }
    hasPendingProperties() {
        return this.pendingRewriteCount > 0 || Object.keys(this.pendingKeyUpdateCount).length > 0;
    }
}
exports.SegmentPropertiesManager = SegmentPropertiesManager;
//# sourceMappingURL=segmentPropertiesManager.js.map