/**
 * @license
 * Copyright 2022-2024 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { camelize, InternalError } from "#general";
import { AttributeModel, ClusterModel, FeatureMap, FeatureSet } from "#model";
import { AccessControl } from "../AccessControl.js";
import { ValueCaster } from "../state/managed/values/ValueCaster.js";
import { ValueManager } from "../state/managed/values/ValueManager.js";
import { ValuePatcher } from "../state/managed/values/ValuePatcher.js";
import { ValueValidator } from "../state/validation/ValueValidator.js";
class RootSupervisor {
  #generating = /* @__PURE__ */ new Set();
  #cache = /* @__PURE__ */ new WeakMap();
  #featureMap;
  #supportedFeatures;
  #members;
  #root;
  #memberNames;
  #persistentNames;
  /**
   * Create a new supervisor.
   *
   * @param schema the {@link Schema} for the supervised data
   */
  constructor(schema) {
    if (schema instanceof ClusterModel) {
      this.#featureMap = schema.featureMap;
      this.#supportedFeatures = schema.supportedFeatures ?? new FeatureSet();
    } else {
      this.#featureMap = new AttributeModel(FeatureMap);
      this.#supportedFeatures = new FeatureSet();
    }
    this.#members = new Set(schema.activeMembers);
    this.#root = this.#createValueSupervisor(schema);
  }
  get owner() {
    return this.#root.owner;
  }
  get schema() {
    return this.#root.schema;
  }
  get access() {
    return this.#root.access;
  }
  get validate() {
    return this.#root.validate;
  }
  get manage() {
    return this.#root.manage;
  }
  get patch() {
    return this.#root.patch;
  }
  get cast() {
    return this.#root.cast;
  }
  /**
   * The names of all members.
   */
  get memberNames() {
    let names = this.#memberNames;
    if (!names) {
      names = /* @__PURE__ */ new Set();
      for (const member of this.#members) {
        names.add(camelize(member.name));
      }
      this.#memberNames = names;
    }
    return names;
  }
  /**
   * Names of fields configured as non-volatile.
   */
  get persistentNames() {
    let persistent = this.#persistentNames;
    if (!persistent) {
      persistent = /* @__PURE__ */ new Set();
      for (const member of this.#members) {
        if (member.effectiveQuality.nonvolatile || member.effectiveAccess.writable || member.effectiveAccess.fabricScoped) {
          persistent.add(camelize(member.name));
        }
      }
      this.#persistentNames = persistent;
    }
    return persistent;
  }
  /**
   * All available features defined in the schema.
   */
  get featureMap() {
    return this.#featureMap;
  }
  /**
   * Features supported by this implementation.
   */
  get supportedFeatures() {
    return this.#supportedFeatures;
  }
  /**
   * Obtain {@link ValueSupervisor} implementation for a specific schema.
   *
   * @param schema the model describing the record type
   * @returns the I/O implementation
   */
  get(schema) {
    if (schema === this.#root?.schema) {
      return this;
    }
    let supervisor = this.#cache.get(schema);
    if (supervisor === void 0) {
      supervisor = this.#createValueSupervisor(schema);
      this.#cache.set(schema, supervisor);
    }
    return supervisor;
  }
  #createValueSupervisor(schema) {
    const deferGeneration = (name, generator) => {
      let generated = false;
      return (...args) => {
        if (!generated) {
          if (manager === void 0) {
            throw new InternalError("Deferred I/O generation invoked impossibly early");
          }
          manager[name] = generator(schema, this);
          generated = true;
        }
        return manager[name](...args);
      };
    };
    let manager;
    if (this.#isGenerating(schema)) {
      manager = {
        owner: this,
        schema,
        access: AccessControl(schema),
        validate: deferGeneration("validate", ValueValidator),
        manage: deferGeneration("manage", ValueManager),
        patch: deferGeneration("patch", ValuePatcher),
        cast: deferGeneration("cast", ValueCaster)
      };
    } else {
      try {
        this.#generating.add(schema);
        manager = {
          owner: this,
          schema,
          access: AccessControl(schema),
          validate: ValueValidator(schema, this),
          manage: ValueManager(schema, this),
          patch: ValuePatcher(schema, this),
          cast: ValueCaster(schema, this)
        };
      } finally {
        this.#generating.delete(schema);
      }
    }
    this.#cache.set(schema, manager);
    return manager;
  }
  /**
   * If a schema has circular references, code generation may need to defer generation of child functions to avoid
   * infinite loops.
   *
   * In order to keep generation code simpler we use this method to detect when lazy generation is necessary and
   * install stubs that bootstrap each method.
   */
  #isGenerating(schema) {
    return this.#generating.has(schema);
  }
}
export {
  RootSupervisor
};
//# sourceMappingURL=RootSupervisor.js.map
