/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { Type } from "@sinclair/typebox";
import { makeCodecFamily, unitCodec } from "../../codec";
import { EncodedOptionalChangeset, EncodedRegisterId } from "./optionalFieldChangeFormat";
export const noChangeCodecFamily = makeCodecFamily([[0, unitCodec]]);
export const makeOptionalFieldCodecFamily = (childCodec, revisionTagCodec) => makeCodecFamily([[0, makeOptionalFieldCodec(childCodec, revisionTagCodec)]]);
function makeRegisterIdCodec(revisionTagCodec) {
    return {
        encode: (registerId) => {
            if (registerId === "self") {
                return 0;
            }
            const encodedRegisterId = { localId: registerId.localId };
            if (registerId.revision !== undefined) {
                encodedRegisterId.revision = revisionTagCodec.encode(registerId.revision);
            }
            return encodedRegisterId;
        },
        decode: (registerId) => {
            if (registerId === 0) {
                return "self";
            }
            const decodedRegisterId = { localId: registerId.localId };
            if (registerId.revision !== undefined) {
                decodedRegisterId.revision = revisionTagCodec.decode(registerId.revision);
            }
            return decodedRegisterId;
        },
        encodedSchema: EncodedRegisterId,
    };
}
function makeOptionalFieldCodec(childCodec, revisionTagCodec) {
    const registerIdCodec = makeRegisterIdCodec(revisionTagCodec);
    return {
        encode: (change) => {
            const encoded = {};
            if (change.moves.length > 0) {
                encoded.m = [];
                for (const [src, dst, type] of change.moves) {
                    encoded.m.push([
                        registerIdCodec.encode(src),
                        registerIdCodec.encode(dst),
                        type === "nodeTargeting",
                    ]);
                }
            }
            if (change.childChanges.length > 0) {
                encoded.c = [];
                for (const [id, childChange] of change.childChanges) {
                    encoded.c.push([registerIdCodec.encode(id), childCodec.encode(childChange)]);
                }
            }
            if (change.reservedDetachId !== undefined) {
                encoded.d = registerIdCodec.encode(change.reservedDetachId);
            }
            return encoded;
        },
        decode: (encoded) => {
            const moves = encoded.m?.map(([src, dst, type]) => [
                registerIdCodec.decode(src),
                registerIdCodec.decode(dst),
                type ? "nodeTargeting" : "cellTargeting",
            ]) ?? [];
            const decoded = {
                moves,
                childChanges: encoded.c?.map(([id, encodedChange]) => [
                    registerIdCodec.decode(id),
                    childCodec.decode(encodedChange),
                ]) ?? [],
            };
            if (encoded.d !== undefined) {
                decoded.reservedDetachId = registerIdCodec.decode(encoded.d);
            }
            return decoded;
        },
        encodedSchema: EncodedOptionalChangeset(childCodec.encodedSchema ?? Type.Any()),
    };
}
//# sourceMappingURL=optionalFieldCodecs.js.map