"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.oneFromSet = exports.treeShaper = exports.fieldShaper = exports.buildCache = exports.schemaCompressedEncode = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const core_1 = require("../../../core");
const util_1 = require("../../../util");
const multiplicity_1 = require("../../multiplicity");
const compressedEncode_1 = require("./compressedEncode");
const nodeShape_1 = require("./nodeShape");
/**
 * Encode data from `cursor` in into an `EncodedChunk`.
 *
 * Optimized for encoded size and encoding performance.
 * TODO: This function should eventually also take in the root FieldSchema to more efficiently compress the nodes.
 */
function schemaCompressedEncode(schema, policy, cursor) {
    return (0, compressedEncode_1.compressedEncode)(cursor, buildCache(schema, policy));
}
exports.schemaCompressedEncode = schemaCompressedEncode;
function buildCache(schema, policy) {
    const cache = new compressedEncode_1.EncoderCache((fieldHandler, schemaName) => treeShaper(schema, policy, fieldHandler, schemaName), (treeHandler, field) => fieldShaper(treeHandler, field, cache), policy.fieldKinds);
    return cache;
}
exports.buildCache = buildCache;
/**
 * Selects shapes to use to encode fields.
 */
function fieldShaper(treeHandler, field, cache) {
    const kind = cache.fieldShapes.get(field.kind.identifier) ?? (0, util_1.fail)("missing FieldKind");
    const type = oneFromSet(field.types);
    const nodeEncoder = type !== undefined ? treeHandler.shapeFromTree(type) : compressedEncode_1.anyNodeEncoder;
    // eslint-disable-next-line unicorn/prefer-ternary
    if (kind.multiplicity === multiplicity_1.Multiplicity.Single) {
        return (0, compressedEncode_1.asFieldEncoder)(nodeEncoder);
    }
    else {
        return cache.nestedArray(nodeEncoder);
    }
}
exports.fieldShaper = fieldShaper;
/**
 * Selects shapes to use to encode trees.
 */
function treeShaper(fullSchema, policy, fieldHandler, schemaName) {
    const schema = fullSchema.nodeSchema.get(schemaName) ?? (0, util_1.fail)("missing schema");
    // TODO:Performance:
    // consider moving some optional and sequence fields to extra fields if they are commonly empty
    // to reduce encoded size.
    const objectNodeFields = [];
    for (const [key, field] of schema.objectNodeFields ?? []) {
        objectNodeFields.push({ key, shape: fieldHandler.shapeFromField(field) });
    }
    const shape = new nodeShape_1.NodeShape(schemaName, valueShapeFromSchema(schema.leafValue), objectNodeFields, schema.mapFields === undefined ? undefined : fieldHandler.shapeFromField(schema.mapFields));
    return shape;
}
exports.treeShaper = treeShaper;
function oneFromSet(set) {
    if (set === undefined) {
        return undefined;
    }
    if (set.size !== 1) {
        return undefined;
    }
    for (const item of set) {
        return item;
    }
}
exports.oneFromSet = oneFromSet;
function valueShapeFromSchema(schema) {
    switch (schema) {
        case undefined:
            return false;
        case core_1.ValueSchema.Number:
        case core_1.ValueSchema.String:
        case core_1.ValueSchema.Boolean:
        case core_1.ValueSchema.FluidHandle:
            return true;
        case core_1.ValueSchema.Null:
            return [null];
        default:
            (0, core_utils_1.unreachableCase)(schema);
    }
}
//# sourceMappingURL=schemaBasedEncoding.js.map