Show:
/**
 * @module  ecs
 */

// forced to disable this check for abstract methods
// jshint unused:false
/**
 * @class  System
 *
 * @description  A system update all eligible entities at a given frequency.
 * This class is not meant to be used directly and should be sub-classed to
 * define specific logic.
 */
class System {
  /**
   * @class  System
   * @constructor
   * @param [frequency=1] {Number} Frequency of execution.
   */
  constructor(frequency=1) {
    /**
     * Frequency of update execution, a frequency of `1` run the system every
     * update, `2` will run the system every 2 updates, ect.
     * @property {Number} frequency
     */
    this.frequency = frequency;

    /**
     * Entities of the system.
     *
     * @property {Array[Entity]} entities
     */
    this.entities = [];
  }
  /**
   * Add an entity to the system entities.
   *
   * @param {Entity} entity The entity to add to the system.
   */
  addEntity(entity) {
    entity.addSystem(this);
    this.entities.push(entity);

    this.enter(entity);
  }
  /**
   * Remove an entity from the system entities. exit() handler is executed
   * only if the entity actually exists in the system entities.
   *
   * @param  {Entity} entity Reference of the entity to remove.
   */
  removeEntity(entity) {
    let index = this.entities.indexOf(entity);

    if (index !== -1) {
      entity.removeSystem(this);
      this.entities.splice(index, 1);

      this.exit(entity);
    }
  }
  /**
   * Apply update to each entity of this system.
   *
   * @method  updateAll
   */
  updateAll(elapsed) {
    this.preUpdate();

    for (let i = 0, entity; entity = this.entities[i]; i += 1) {
      this.update(entity, elapsed);
    }

    this.postUpdate();
  }
  /**
   * dispose the system by exiting all the entities
   *
   * @method  dispose
   */
  dispose() {
    for (let i = 0, entity; entity = this.entities[i]; i += 1) {
      entity.removeSystem(this);
      this.exit(entity);
    }
  }
  // methods to be extended by subclasses
  /**
   * Abstract method to subclass. Called once per update, before entities
   * iteration.
   *
   * @method  preUpdate
   */
  preUpdate() {}
  /**
   * Abstract method to subclass. Called once per update, after entities
   * iteration.
   *
   * @method  postUpdate
   */
  postUpdate() {}
  /**
   * Abstract method to subclass. Should return true if the entity is eligible
   * to the system, false otherwise.
   *
   * @method  test
   * @param  {Entity} entity The entity to test.
   */
  test(entity) {
    return false;
  }
  /**
   * Abstract method to subclass. Called when an entity is added to the system.
   *
   * @method  enter
   * @param  {Entity} entity The added entity.
   */
  enter(entity) {}
  /**
   * Abstract method to subclass. Called when an entity is removed from the system.
   *
   * @method  exit
   * @param  {Entity} entity The removed entity.
   */
  exit(entity) {}
  /**
   * Abstract method to subclass. Called for each entity to update. This is
   * the only method that should actual mutate entity state.
   *
   * @method  update
   * @param  {Entity} entity The entity to update.
   */
  update(entity) {}
}
// jshint unused:true

export default System;