"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientVersionDispatchingCodecBuilder = exports.makeVersionDispatchingCodec = exports.makeVersionedValidatedCodec = exports.makeVersionedCodec = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const internal_2 = require("@fluidframework/telemetry-utils/internal");
const codec_js_1 = require("../codec.js");
const format_js_1 = require("./format.js");
const packageVersion_js_1 = require("../../packageVersion.js");
function makeVersionedCodec(supportedVersions, { jsonValidator: validator }, inner) {
    const codec = {
        encode: (data, context) => {
            const encoded = inner.encode(data, context);
            (0, internal_1.assert)(supportedVersions.has(encoded.version), 0x88b /* version being encoded should be supported */);
            return encoded;
        },
        decode: (data, context) => {
            const versioned = data; // Validated by withSchemaValidation
            if (!supportedVersions.has(versioned.version)) {
                throw new internal_2.UsageError(`Unsupported version ${versioned.version} encountered while decoding data. Supported versions for this data are: ${Array.from(supportedVersions).join(", ")}.
The client which encoded this data likely specified an "oldestCompatibleClient" value which corresponds to a version newer than the version of this client ("${packageVersion_js_1.pkgVersion}").`);
            }
            const decoded = inner.decode(data, context);
            return decoded;
        },
    };
    return supportedVersions.has(undefined)
        ? codec
        : (0, codec_js_1.withSchemaValidation)(format_js_1.Versioned, codec, validator);
}
exports.makeVersionedCodec = makeVersionedCodec;
function makeVersionedValidatedCodec(options, supportedVersions, schema, codec) {
    return makeVersionedCodec(supportedVersions, options, (0, codec_js_1.withSchemaValidation)(schema, codec, options.jsonValidator));
}
exports.makeVersionedValidatedCodec = makeVersionedValidatedCodec;
/**
 * Creates a codec which dispatches to the appropriate member of a codec family based on the version of
 * data it encounters.
 * @remarks
 * Each member of the codec family must write an explicit version number into the data it encodes (implementing {@link Versioned}).
 *
 * TODO: Users of this should migrate to {@link ClientVersionDispatchingCodecBuilder} so that the actual format version used can be encapsulated.
 */
function makeVersionDispatchingCodec(family, options) {
    const writeCodec = family.resolve(options.writeVersion).json;
    const supportedVersions = new Set(family.getSupportedFormats());
    return makeVersionedCodec(supportedVersions, options, {
        encode(data, context) {
            return writeCodec.encode(data, context);
        },
        decode(data, context) {
            const codec = family.resolve(data.version);
            return codec.json.decode(data, context);
        },
    });
}
exports.makeVersionDispatchingCodec = makeVersionDispatchingCodec;
/**
 * Creates a codec which dispatches to the appropriate member of a codec family based on the `oldestCompatibleClient` for encode and the
 * version number in data it encounters for decode.
 * @privateRemarks
 * This is a two stage builder so the first stage can encapsulate all codec specific details and the second can bring in configuration.
 */
class ClientVersionDispatchingCodecBuilder {
    constructor(
    /**
     * The codec family to dispatch to.
     */
    family, 
    /**
     * A function which maps a {@link FluidClientVersion} to a version number for the codec family which is supported by that version.
     * This can (and typically does) pick the newest version of the codec which is known to be compatible with the client version so that
     * any improvements in newer versions of the codec can be used when allowed.
     */
    versionMapping) {
        this.family = family;
        this.versionMapping = versionMapping;
    }
    build(options) {
        const writeVersion = this.versionMapping(options.oldestCompatibleClient);
        return makeVersionDispatchingCodec(this.family, { ...options, writeVersion });
    }
}
exports.ClientVersionDispatchingCodecBuilder = ClientVersionDispatchingCodecBuilder;
//# sourceMappingURL=codec.js.map