"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeModularChangeCodecFamily = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
const core_1 = require("../../core");
const util_1 = require("../../util");
const codec_1 = require("../../codec");
const genericFieldKind_1 = require("./genericFieldKind");
function makeV0Codec(fieldKinds) {
    const nodeChangesetCodec = {
        encode: encodeNodeChangesForJson,
        decode: decodeNodeChangesetFromJson,
    };
    const fieldChangesetCodecs = new Map([
        [
            genericFieldKind_1.genericFieldKind.identifier,
            genericFieldKind_1.genericFieldKind.changeHandler.codecsFactory(nodeChangesetCodec).resolve(0),
        ],
    ]);
    fieldKinds.forEach((fieldKind, identifier) => {
        const codec = fieldKind.changeHandler.codecsFactory(nodeChangesetCodec).resolve(0);
        fieldChangesetCodecs.set(identifier, codec);
    });
    const getFieldChangesetCodec = (fieldKind) => {
        const codec = fieldChangesetCodecs.get(fieldKind);
        (0, common_utils_1.assert)(codec !== undefined, 0x5ea /* Tried to encode unsupported fieldKind */);
        return codec;
    };
    function encodeFieldChangesForJson(change) {
        const encodedFields = [];
        for (const [field, fieldChange] of change) {
            const encodedChange = getFieldChangesetCodec(fieldChange.fieldKind).json.encode(fieldChange.change);
            const global = (0, core_1.isGlobalFieldKey)(field);
            const fieldKey = global ? (0, core_1.keyFromSymbol)(field) : field;
            const encodedField = {
                fieldKey,
                keyIsGlobal: global,
                fieldKind: fieldChange.fieldKind,
                change: encodedChange,
            };
            encodedFields.push(encodedField);
        }
        return encodedFields;
    }
    function encodeNodeChangesForJson(change) {
        const encodedChange = {};
        if (change.valueChange !== undefined) {
            encodedChange.valueChange = change.valueChange;
        }
        if (change.fieldChanges !== undefined) {
            const encodedFieldChanges = encodeFieldChangesForJson(change.fieldChanges);
            encodedChange.fieldChanges = encodedFieldChanges;
        }
        if (change.valueConstraint !== undefined) {
            encodedChange.valueConstraint = change.valueConstraint;
        }
        return encodedChange;
    }
    function decodeFieldChangesFromJson(encodedChange) {
        const decodedFields = new Map();
        for (const field of encodedChange) {
            const fieldChangeset = getFieldChangesetCodec(field.fieldKind).json.decode(field.change);
            const fieldKey = field.keyIsGlobal
                ? (0, core_1.symbolFromKey)((0, util_1.brand)(field.fieldKey))
                : (0, util_1.brand)(field.fieldKey);
            decodedFields.set(fieldKey, {
                fieldKind: field.fieldKind,
                change: (0, util_1.brand)(fieldChangeset),
            });
        }
        return decodedFields;
    }
    function decodeNodeChangesetFromJson(change) {
        const encodedChange = change;
        const decodedChange = {};
        if (encodedChange.valueChange !== undefined) {
            decodedChange.valueChange = encodedChange.valueChange;
        }
        if (encodedChange.fieldChanges !== undefined) {
            decodedChange.fieldChanges = decodeFieldChangesFromJson(encodedChange.fieldChanges);
        }
        if (encodedChange.valueConstraint !== undefined) {
            decodedChange.valueConstraint = encodedChange.valueConstraint;
        }
        return decodedChange;
    }
    return {
        encode: (change) => {
            return {
                maxId: change.maxId,
                revisions: change.revisions,
                changes: encodeFieldChangesForJson(change.fieldChanges),
            };
        },
        decode: (change) => {
            const encodedChange = change;
            const decoded = {
                fieldChanges: decodeFieldChangesFromJson(encodedChange.changes),
            };
            if (encodedChange.revisions !== undefined) {
                decoded.revisions = encodedChange.revisions;
            }
            if (encodedChange.maxId !== undefined) {
                decoded.maxId = encodedChange.maxId;
            }
            return decoded;
        },
    };
}
function makeModularChangeCodecFamily(fieldKinds) {
    return (0, codec_1.makeCodecFamily)([[0, makeV0Codec(fieldKinds)]]);
}
exports.makeModularChangeCodecFamily = makeModularChangeCodecFamily;
//# sourceMappingURL=modularChangeCodecs.js.map