import { LogUtility } from '../../utils/log';
/**
 * The ChangeManager is a class that allows observers to register themselves to a subject
 * and notify the observer if signaled by subject
 *
 * @requires Subject
 * @requires Observer
 * @property {Map<Subject, Observer<unknown>[]>} pubSubMap - the map of subject to observers
 */
class ChangeManager {
  constructor() {
    this.pubSubMap = new Map();
  }
  /**
   * If the subject is already in the map, add the observer to the list of observers for that subject. If the subject is not
   * in the map, add the subject to the map and add the observer to the list of observers for that subject
   *
   * @param {Subject} subject - The subject of the event.
   * @param {Observer<unknown>} observer - The observer that will be registered.
   */
  register(subject, observer) {
    if (this.pubSubMap.has(subject)) {
      const observers = this.pubSubMap.get(subject);
      if (observers && !observers.includes(observer)) {
        observers.push(observer);
      }
    }
    else {
      this.pubSubMap.set(subject, [observer]);
    }
  }
  /**
   * If the subject is in the map, remove the observer from the list of observers for that subject
   *
   * @param {Subject} subject - The subject of the event.
   * @param {Observer<unknown>} observer - The observer to be unregistered.
   */
  unregister(subject, observer) {
    if (this.pubSubMap.has(subject)) {
      const observers = this.pubSubMap.get(subject);
      if (observers && observers.includes(observer)) {
        observers.splice(observers.indexOf(observer), 1);
      }
    }
  }
  /**
   * The function clears the observers for a given subject in a pub-sub map.
   *
   * @param {Subject} subject - The subject parameter is an object that represents the subject of the observer pattern. It is used as a key to identify the observers that are subscribed to it.
   */
  clearObserversBySubject(subject) {
    this.pubSubMap.delete(subject);
  }
  /**
   * If the subject is in the map, then notify all observers of the subject
   *
   * @param {Subject} subject - Subject
   * @param {unknown} payload - The payload to be sent to the observer.
   */
  notify(subject, payload) {
    if (this.pubSubMap.has(subject)) {
      this.pubSubMap.get(subject).forEach((observer) => {
        try {
          observer.notify(payload);
        }
        catch (e) {
          LogUtility.warn(`Encountered error while notifying observer for subject ${subject.getDescription()}`, e);
        }
      });
    }
  }
}
export default new ChangeManager();
