Source: observers.js

'use strict'

/**
 * @module observers
 */
export const observers = {};

/**
 * The Subject type.
 *
 * The observer pattern is a software design pattern in which an object, named the subject,
 * maintains a list of its dependents, called observers, and notifies them automatically of
 * any state changes, usually by calling one of their methods.
 *
 * @memberOf module:observers
 * @constructor
 * @struct
 * @final
 */
observers.Subject = function () {

  const observers = {};

  /**
   * Returns the number of observers for a given message type.
   *
   * @param {string} message  the observed message.
   * @return {number} the number of observers.
   */
  this.numberOfObservers = function (message) {
    if (message) {
      return observers.hasOwnProperty(message) ? observers[message].length : 0;
    }
    let nbObservers = 0;
    for (const msg in observers) {
      nbObservers += observers[msg].length
    }
    return nbObservers;
  }

  /**
   * Register a callback for a given message type.
   *
   * @param {string} message the message to observe.
   * @param {Function} observer the callback to notify.
   */
  this.register = function (message, observer) {
    if (message && typeof message === 'string' && observer && observer instanceof Function) {
      if (!observers.hasOwnProperty(message)) {
        observers[message] = [];
      }
      observers[message].push(observer);
    }
  }

  /**
   * Unregister a callback for a given message type.
   *
   * @param {string} message the observed message.
   * @param {Function} observer the notified callback.
   */
  this.unregister = function (message, observer) {
    if (message && typeof message === 'string' && observer && observer instanceof Function && observers.hasOwnProperty(
        message)) {
      observers[message] = observers[message].filter(o => o !== observer);
    }
  }

  /**
   * Notify all observers listening to a given message type.
   *
   * @param {string} message the message type.
   * @param {...*} args a list of arguments to pass to each callback.
   */
  this.notify = function (message, ...args) {
    if (message && typeof message === 'string' && args && observers.hasOwnProperty(message)) {
      observers[message].forEach(observer => observer(...args));
    }
  }
}