"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapSchema = void 0;
const index_js_1 = require("../feature-libraries/index.js");
const proxies_js_1 = require("./proxies.js");
const proxyBinding_js_1 = require("./proxyBinding.js");
const schemaTypes_js_1 = require("./schemaTypes.js");
const index_js_2 = require("./core/index.js");
const toMapTree_js_1 = require("./toMapTree.js");
const toFlexSchema_js_1 = require("./toFlexSchema.js");
const index_js_3 = require("../util/index.js");
const treeNodeValid_js_1 = require("./treeNodeValid.js");
const handler = {
    getPrototypeOf: () => {
        return Map.prototype;
    },
};
class CustomMapNodeBase extends treeNodeValid_js_1.TreeNodeValid {
    [Symbol.iterator]() {
        return this.entries();
    }
    get innerNode() {
        return (0, proxyBinding_js_1.getOrCreateInnerNode)(this);
    }
    editor(key) {
        const field = this.innerNode.getBoxed((0, index_js_3.brand)(key));
        return field.editor;
    }
    delete(key) {
        const field = this.innerNode.getBoxed((0, index_js_3.brand)(key));
        this.editor(key).set(undefined, field.length === 0);
    }
    *entries() {
        const node = this.innerNode;
        for (const key of node.keys()) {
            yield [
                key,
                (0, proxies_js_1.getTreeNodeForField)(node.getBoxed(key)),
            ];
        }
    }
    get(key) {
        const node = this.innerNode;
        const field = node.getBoxed((0, index_js_3.brand)(key));
        return (0, proxies_js_1.getTreeNodeForField)(field);
    }
    has(key) {
        return this.innerNode.tryGetField((0, index_js_3.brand)(key)) !== undefined;
    }
    keys() {
        const node = this.innerNode;
        return node.keys();
    }
    set(key, value) {
        const kernel = (0, index_js_2.getKernel)(this);
        const node = this.innerNode;
        const mapTree = (0, toMapTree_js_1.mapTreeFromNodeData)(value, (0, schemaTypes_js_1.createFieldSchema)(schemaTypes_js_1.FieldKind.Optional, kernel.schema.info), node.context.isHydrated() ? node.context.nodeKeyManager : undefined, (0, index_js_1.getSchemaAndPolicy)(node));
        const field = node.getBoxed((0, index_js_3.brand)(key));
        if (node.context.isHydrated()) {
            (0, proxies_js_1.prepareContentForHydration)(mapTree, node.context.checkout.forest);
        }
        this.editor(key).set(mapTree, field.length === 0);
        return this;
    }
    get size() {
        return (0, index_js_3.count)(this.innerNode.keys());
    }
    *values() {
        for (const [, value] of this.entries()) {
            yield value;
        }
    }
    forEach(callbackFn, thisArg) {
        for (const field of (0, proxyBinding_js_1.getOrCreateInnerNode)(this).boxedIterator()) {
            const node = (0, proxies_js_1.getTreeNodeForField)(field);
            callbackFn.call(thisArg, node, field.key, this);
        }
    }
}
CustomMapNodeBase.kind = index_js_2.NodeKind.Map;
/**
 * Define a {@link TreeNodeSchema} for a {@link (TreeArrayNode:interface)}.
 *
 * @param base - base schema type to extend.
 * @param useMapPrototype - should this type emulate a ES6 Map object (by faking its prototype with a proxy).
 */
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function mapSchema(identifier, info, implicitlyConstructable, useMapPrototype) {
    let flexSchema;
    let unhydratedContext;
    class Schema extends CustomMapNodeBase {
        static prepareInstance(instance, flexNode) {
            if (useMapPrototype) {
                return new Proxy(instance, handler);
            }
            return instance;
        }
        static buildRawNode(instance, input) {
            return (0, index_js_1.getOrCreateMapTreeNode)(unhydratedContext, flexSchema, (0, toMapTree_js_1.mapTreeFromNodeData)(input, this));
        }
        static oneTimeSetup() {
            const schema = this;
            flexSchema = (0, toFlexSchema_js_1.getFlexSchema)(schema);
            unhydratedContext = new index_js_1.UnhydratedContext((0, toFlexSchema_js_1.toFlexSchema)(schema));
        }
        // eslint-disable-next-line import/no-deprecated
        get [index_js_2.typeNameSymbol]() {
            return identifier;
        }
        get [index_js_2.typeSchemaSymbol]() {
            return Schema.constructorCached?.constructor;
        }
    }
    Schema.constructorCached = undefined;
    Schema.identifier = identifier;
    Schema.info = info;
    Schema.implicitlyConstructable = implicitlyConstructable;
    const schemaErased = Schema;
    return schemaErased;
}
exports.mapSchema = mapSchema;
//# sourceMappingURL=mapNode.js.map