core/Model.js

/*
 *  Model.js
 *  PureMVC JavaScript Multicore
 *
 *  Copyright(c) 2023 Saad Shams <saad.shams@puremvc.org>
 *  Your reuse is governed by the BSD License
*/

/**
 * A Multiton `Model` implementation.
 *
 * <P>In PureMVC, the `Model` class provides
 * access to model objects (Proxies) by named lookup.
 *
 * <P>The `Model` assumes these responsibilities:</P>
 *
 * <UL>
 * <LI>Maintain a cache of `Proxy` instances.</LI>
 * <LI>Provide methods for registering, retrieving, and removing
 * `Proxy` instances.</LI>
 * </UL>
 *
 * <P>Your application must register `Proxy` instances
 * with the `Model`. Typically, you use an
 * `Command` to create and register `Proxy`
 * instances once the `Facade` has initialized the Core
 * actors.</p>
 *
 * @see Proxy Proxy
 *
 * @class Model
 */

class Model {

    /**
     * Constructor.
     *
     * <P>This `Model` implementation is a Multiton,
     * so you should not call the constructor
     * directly, but instead call the static Multiton
     * Factory method `Model.getInstance( multitonKey )`
     *
     * @constructor
     * @param {string} key
     *
     * @throws {Error} Error if instance for this Multiton key instance has already been constructed
     */
    constructor(key) {
        if (Model.instanceMap.get(key) != null) throw new Error(Model.MULTITON_MSG);
        /** @protected
         * @type {string} */
        this.multitonKey = key;
        Model.instanceMap.set(this.multitonKey, this);
        /** @protected
         * @type {Map<string, Proxy>} */
        this.proxyMap = new Map();
        this.initializeModel();
    }

    /**
     * Initialize the `Model` instance.
     *
     * <P>Called automatically by the constructor, this
     * is your opportunity to initialize the Multiton
     * instance in your subclass without overriding the
     * constructor.</P>
     *
     */
    initializeModel() {

    }

    /**
     * `Model` Multiton Factory method.
     *
     * @static
     * @param {string} key
     * @param {function(string):Model} factory
     * @returns {Model} the instance for this Multiton key
     */
    static getInstance(key, factory) {
        if (Model.instanceMap == null)
            /** @static
             @type {Map<string, Model>} */
            Model.instanceMap = new Map();
        if (Model.instanceMap.get(key) == null) Model.instanceMap.set(key, factory(key));
        return Model.instanceMap.get(key);
    }

    /**
     * Register a `Proxy` with the `Model`.
     *
     * @param {Proxy} proxy a `Proxy` to be held by the `Model`.
     */
    registerProxy(proxy) {
        proxy.initializeNotifier(this.multitonKey);
        this.proxyMap.set(proxy.proxyName, proxy);
        proxy.onRegister();
    }

    /**
     * Retrieve a `Proxy` from the `Model`.
     *
     * @param {string} proxyName
     * @returns {Proxy} the `Proxy` instance previously registered with the given `proxyName`.
     */
    retrieveProxy(proxyName) {
        return this.proxyMap.get(proxyName) || null;
    }

    /**
     * Check if a Proxy is registered
     *
     * @param {string} proxyName
     * @returns {boolean} whether a Proxy is currently registered with the given `proxyName`.
     */
    hasProxy(proxyName) {
        return this.proxyMap.has(proxyName);
    }

    /**
     * Remove a `Proxy` from the `Model`.
     *
     * @param {string} proxyName name of the `Proxy` instance to be removed.
     * @returns {Proxy} the `Proxy` that was removed from the `Model`
     */
    removeProxy(proxyName) {
        let proxy = this.proxyMap.get(proxyName);
        if (proxy != null) {
            this.proxyMap.delete(proxyName);
            proxy.onRemove();
        }
        return proxy;
    }

    /**
     * Remove a Model instance
     *
     * @static
     * @param key
     */
    static removeModel(key) {
        Model.instanceMap.delete(key);
    }

    /**
     * @static
     * @type {string}
     */
    static get MULTITON_MSG() { return "Model instance for this Multiton key already constructed!" };
}
export { Model }