Home Reference Source

src/systems/System.js

import Events from '../utils/Events';
import { findMapKeyOfValue } from '../utils';

const _systems = new Map();
const _events = new Events();

/**
 * System base class.
 * Every Oxygen Core system extends this class.
 */
export default class System {

  /** @type {*} */
  static get systems() {
    const result = {};

    for (const [name, system] of _systems) {
      result[name] = system;
    }

    return result;
  }

  /** @type {Events} */
  static get events() {
    return _events;
  }

  /**
   * Register new system instance under given name.
   *
   * @param {string}	typename - System type name.
   * @param {System}	system - System instance.
   *
   * @return {System} Registered system instance.
   *
   * @example
   * class MySystem extends System {}
   * System.register('MySystem', new MySystem());
   * const { MySystem } = System.systems;
   */
  static register(typename, system) {
    if (typeof typename !== 'string') {
      throw new Error('`typename` is not type of String!');
    }
    if (!(system instanceof System)) {
      throw new Error('`system` is not type of System!');
    }

    if (_systems.has(typename)) {
      throw new Error(`Given system type is already registered: ${typename}`);
    }

    _systems.set(typename, system);
    system.onRegister();
    return system;
  }

  /**
   * Unregister given system.
   *
   * @param {string}	typename - System type name
   *
   * @return {System} Unregistered system instance.
   * @example
   * System.unregister('MySystem');
   */
  static unregister(typename) {
    let system = typename;

    if (typeof typename === 'string') {
      system = _systems.get(typename);
    } else if (system instanceof System) {
      typename = findMapKeyOfValue(_systems, system);
    } else {
      throw new Error('`typename` is not type of either System or String!');
    }

    if (_systems.delete(typename)) {
      system.onUnregister();
      return system;
    } else {
      throw new Error(`Trying to remove non-registered system type: ${typename}`);
    }
  }

  /**
   * Returns system instance of given type name.
   *
   * @param {string}	typename - System type name.
   *
   * @return {System|null} System instance if registered or null if not.
   *
   * @example
   * const system = System.get('MySystem');
   */
  static get(typename) {
    if (typeof typename !== 'string') {
      throw new Error('`typename` is not type of String!');
    }

    return _systems.get(typename) || null;
  }

  /**
   * Dispose and remove all registered systems.
   *
   * @example
   * System.dispose();
   */
  static dispose() {
    for (const system of _systems.values()) {
      system.dispose();
    }

    _systems.clear();
    _events.dispose();
  }

  /**
   * Destructor (disposes all internal resources).
   */
  dispose() {}

  /**
   * Event called after system gets registered.
   */
  onRegister() {}

  /**
   * Event called before system gets unregistered.
   */
  onUnregister() {}

}