"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeFieldShapes = exports.NodeShape = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
const core_1 = require("../../../core");
const util_1 = require("../../../util");
const chunkEncodingGeneric_1 = require("./chunkEncodingGeneric");
const compressedEncode_1 = require("./compressedEncode");
class NodeShape extends chunkEncodingGeneric_1.Shape {
    constructor(type, value, fields, extraLocal) {
        super();
        this.type = type;
        this.value = value;
        this.fields = fields;
        this.extraLocal = extraLocal;
        this.explicitKeys = new Set(this.fields.map((f) => f.key));
    }
    encodeNode(cursor, cache, outputBuffer) {
        if (this.type === undefined) {
            outputBuffer.push(new chunkEncodingGeneric_1.IdentifierToken(cursor.type));
        }
        else {
            (0, common_utils_1.assert)(cursor.type === this.type, 0x741 /* type must match shape */);
        }
        (0, compressedEncode_1.encodeValue)(cursor.value, this.value, outputBuffer);
        for (const field of this.fields) {
            cursor.enterField((0, util_1.brand)(field.key));
            field.shape.encodeField(cursor, cache, outputBuffer);
            cursor.exitField();
        }
        const localBuffer = [];
        (0, core_1.forEachField)(cursor, () => {
            const key = cursor.getFieldKey();
            if (!this.explicitKeys.has(key)) {
                (0, common_utils_1.assert)(this.extraLocal !== undefined, 0x742 /* had extra local fields when shape does not support them */);
                localBuffer.push(new chunkEncodingGeneric_1.IdentifierToken(key));
                this.extraLocal.encodeField(cursor, cache, localBuffer);
            }
        });
        if (this.extraLocal !== undefined) {
            outputBuffer.push(localBuffer);
        }
    }
    encodeShape(identifiers, shapes) {
        return {
            c: {
                type: encodeOptionalIdentifier(this.type, identifiers),
                value: this.value,
                fields: encodeFieldShapes(this.fields, identifiers, shapes),
                extraFields: encodeOptionalFieldShape(this.extraLocal, shapes),
            },
        };
    }
    count(identifiers, shapes) {
        if (this.type !== undefined) {
            identifiers.add(this.type);
        }
        for (const field of this.fields) {
            identifiers.add(field.key);
            shapes(field.shape.shape);
        }
        if (this.extraLocal !== undefined) {
            shapes(this.extraLocal.shape);
        }
    }
    get shape() {
        return this;
    }
}
exports.NodeShape = NodeShape;
function encodeFieldShapes(fields, identifiers, shapes) {
    return fields.map((field) => ({
        key: encodeIdentifier(field.key, identifiers),
        shape: shapes.valueToIndex.get(field.shape.shape) ?? (0, util_1.fail)("missing shape"),
    }));
}
exports.encodeFieldShapes = encodeFieldShapes;
function encodeIdentifier(identifier, identifiers) {
    return identifiers.valueToIndex.get(identifier) ?? identifier;
}
function encodeOptionalIdentifier(identifier, identifiers) {
    return identifier === undefined ? undefined : encodeIdentifier(identifier, identifiers);
}
function encodeOptionalFieldShape(shape, shapes) {
    return shape === undefined ? undefined : dedupShape(shape.shape, shapes);
}
function dedupShape(shape, shapes) {
    return shapes.valueToIndex.get(shape) ?? (0, util_1.fail)("missing shape");
}
//# sourceMappingURL=nodeShape.js.map