"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.getFieldKind = exports.buildCache = exports.schemaCompressedEncode = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const core_1 = require("../../../core");
const modular_schema_1 = require("../../modular-schema");
const util_1 = require("../../../util");
const default_field_kinds_1 = require("../../default-field-kinds");
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.
 */
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));
    return cache;
}
exports.buildCache = buildCache;
function getFieldKind(fieldSchema) {
    // TODO:
    // This module currently is assuming use of defaultFieldKinds.
    // The field kinds should instead come from a view schema registry thats provided somewhere.
    return default_field_kinds_1.fieldKinds.get(fieldSchema.kind.identifier) ?? (0, util_1.fail)("missing field kind");
}
exports.getFieldKind = getFieldKind;
/**
 * Selects shapes to use to encode fields.
 */
function fieldShaper(treeHandler, field, cache) {
    const kind = getFieldKind(field);
    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 === modular_schema_1.Multiplicity.Value) {
        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.treeSchema.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 structFields = [];
    for (const [key, field] of schema.structFields ?? []) {
        structFields.push({ key, shape: fieldHandler.shapeFromField(field) });
    }
    const shape = new nodeShape_1.NodeShape(schemaName, valueShapeFromSchema(schema.leafValue), structFields, 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.Serializable:
            return true;
        default:
            (0, core_utils_1.unreachableCase)(schema);
    }
}
//# sourceMappingURL=schemaBasedEncoding.js.map