"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeltaManagerPendingOpsProxy = exports.DeltaManagerSummarizerProxy = exports.BaseDeltaManagerProxy = void 0;
const client_utils_1 = require("@fluid-internal/client-utils");
const index_js_1 = require("./summary/index.js");
/**
 * Base class for DeltaManager proxy that proxy's access to the real DeltaManager.
 *
 * This class allows us to build proxy functionality without actually having to implement all the methods
 * of the DeltaManager.
 */
class BaseDeltaManagerProxy extends client_utils_1.TypedEventEmitter {
    get IDeltaSender() {
        return this;
    }
    get inbound() {
        return this.deltaManager.inbound;
    }
    get outbound() {
        return this.deltaManager.outbound;
    }
    get inboundSignal() {
        return this.deltaManager.inboundSignal;
    }
    get minimumSequenceNumber() {
        return this.deltaManager.minimumSequenceNumber;
    }
    get lastSequenceNumber() {
        return this.deltaManager.lastSequenceNumber;
    }
    get lastMessage() {
        return this.deltaManager.lastMessage;
    }
    get lastKnownSeqNumber() {
        return this.deltaManager.lastKnownSeqNumber;
    }
    get initialSequenceNumber() {
        return this.deltaManager.initialSequenceNumber;
    }
    get hasCheckpointSequenceNumber() {
        return this.deltaManager.hasCheckpointSequenceNumber;
    }
    get clientDetails() {
        return this.deltaManager.clientDetails;
    }
    get version() {
        return this.deltaManager.version;
    }
    get maxMessageSize() {
        return this.deltaManager.maxMessageSize;
    }
    get serviceConfiguration() {
        return this.deltaManager.serviceConfiguration;
    }
    get active() {
        return this.deltaManager.active;
    }
    get readOnlyInfo() {
        return this.deltaManager.readOnlyInfo;
    }
    constructor(deltaManager) {
        super();
        this.deltaManager = deltaManager;
        this.onPrepareSend = (messageBuffer) => {
            this.emit("prepareSend", messageBuffer);
        };
        this.onSubmitOp = (message) => {
            this.emit("submitOp", message);
        };
        this.onOp = (message, processingTime) => {
            this.emit("op", message, processingTime);
        };
        this.onPong = (latency) => {
            this.emit("pong", latency);
        };
        this.onConnect = (details, opsBehind) => {
            this.emit("connect", details, opsBehind);
        };
        this.onDisconnect = (reason, error) => {
            this.emit("disconnect", reason, error);
        };
        this.onReadonly = (readonly, readonlyConnectionReason) => {
            this.emit("readonly", readonly, readonlyConnectionReason);
        };
        // We are expecting this class to have many listeners, so we suppress noisy "MaxListenersExceededWarning" logging.
        super.setMaxListeners(0);
        this.deltaManager.on("prepareSend", this.onPrepareSend);
        this.deltaManager.on("submitOp", this.onSubmitOp);
        this.deltaManager.on("op", this.onOp);
        this.deltaManager.on("pong", this.onPong);
        this.deltaManager.on("connect", this.onConnect);
        this.deltaManager.on("disconnect", this.onDisconnect);
        this.deltaManager.on("readonly", this.onReadonly);
    }
    dispose() {
        this.deltaManager.off("prepareSend", this.onPrepareSend);
        this.deltaManager.off("submitOp", this.onSubmitOp);
        this.deltaManager.off("op", this.onOp);
        this.deltaManager.off("pong", this.onPong);
        this.deltaManager.off("connect", this.onConnect);
        this.deltaManager.off("disconnect", this.onDisconnect);
        this.deltaManager.off("readonly", this.onReadonly);
    }
    submitSignal(content, targetClientId) {
        return this.deltaManager.submitSignal(content, targetClientId);
    }
    flush() {
        return this.deltaManager.flush();
    }
}
exports.BaseDeltaManagerProxy = BaseDeltaManagerProxy;
/**
 * Proxy to the real IDeltaManager for restricting certain access to layers below container runtime in summarizer clients:
 * - Summarizer client should be read-only to layers below the container runtime to restrict local changes.
 * - Summarizer client should not be active to layers below the container runtime to restrict local changes.
 */
class DeltaManagerSummarizerProxy extends BaseDeltaManagerProxy {
    get active() {
        // Summarize clients should not be active. There shouldn't be any local changes (writes) in the summarizer
        // except for the SummarizeOp which is generated by the runtime.
        return !this.isSummarizerClient && this.deltaManager.active;
    }
    get readOnlyInfo() {
        // Summarizer clients should be read-only as far as the runtime and layers below are concerned. There shouldn't
        // be any local changes (writes) in the summarizer except for the summarize op which is generated by the runtime.
        if (this.isSummarizerClient) {
            return {
                readonly: true,
                forced: false,
                permissions: undefined,
                storageOnly: false,
            };
        }
        return this.deltaManager.readOnlyInfo;
    }
    constructor(deltaManager) {
        super(deltaManager);
        this.deltaManager = deltaManager;
        this.isSummarizerClient = this.deltaManager.clientDetails.type === index_js_1.summarizerClientType;
    }
}
exports.DeltaManagerSummarizerProxy = DeltaManagerSummarizerProxy;
class DeltaManagerPendingOpsProxy extends BaseDeltaManagerProxy {
    get minimumSequenceNumber() {
        const minPendingSeqNum = this.pendingStateManager.minimumPendingMessageSequenceNumber;
        // There is a chance that minPendingSeqNum is greater than minimum sequence number.
        // minPendingSeqNum is based on the pending ops, so it's based on ref seq number.
        // Imagine an op has just be sent while there's another client that has been lagging behind,
        // it will likely have a ref seq number greater than the minimum seq number.
        if (minPendingSeqNum !== undefined &&
            minPendingSeqNum < this.deltaManager.minimumSequenceNumber) {
            return minPendingSeqNum;
        }
        return this.deltaManager.minimumSequenceNumber;
    }
    get lastMessage() {
        if (this.deltaManager.lastMessage === undefined) {
            return this.deltaManager.lastMessage;
        }
        return {
            ...this.deltaManager.lastMessage,
            minimumSequenceNumber: this.minimumSequenceNumber,
        };
    }
    constructor(deltaManager, pendingStateManager) {
        super(deltaManager);
        this.deltaManager = deltaManager;
        this.pendingStateManager = pendingStateManager;
        this.onOp = (message, processingTime) => {
            const messageIntercept = {
                ...message,
                minimumSequenceNumber: this.minimumSequenceNumber,
            };
            this.emit("op", messageIntercept, processingTime);
        };
    }
}
exports.DeltaManagerPendingOpsProxy = DeltaManagerPendingOpsProxy;
//# sourceMappingURL=deltaManagerProxies.js.map