Source: Group.js

goog.provide('entitas.Group');
goog.require('entitas.utils.Signal');
goog.require('entitas.GroupEventType');
goog.require('entitas.exceptions.SingleEntityException');


/**
 * @constructor
 * @param matcher
 */
entitas.Group = function(matcher) {
  /**
   * Subscribe to Entity Addded events
   * @type {entitas.utils.ISignal} */
  this.onEntityAdded = null;
  /**
   * Subscribe to Entity Removed events
   * @type {entitas.utils.ISignal} */
  this.onEntityRemoved = null;
  /**
   * Subscribe to Entity Updated events
   * @type {entitas.utils.ISignal} */
  this.onEntityUpdated = null;
  this._entities = {};
  this._matcher = null;
  this._entitiesCache = null;
  this._singleEntityCache = null;
  this._toStringCache = '';
  this._entities = {};
  this.onEntityAdded = new entitas.utils.Signal(this);
  this.onEntityRemoved = new entitas.utils.Signal(this);
  this.onEntityUpdated = new entitas.utils.Signal(this);
  this._matcher = matcher;
}
Object.defineProperty(entitas.Group.prototype, "count", {
  /**
   * Count the number of entities in this group
   * @type {number}
   * @name entitas.Group#count */
  get: function () { return Object.keys(this._entities).length; },
  enumerable: true,
  configurable: true
});
Object.defineProperty(entitas.Group.prototype, "matcher", {
  /**
   * Get the Matcher for this group
   * @type {entitas.IMatcher}
   * @name entitas.Group#matcher */
  get: function () { return this._matcher; },
  enumerable: true,
  configurable: true
});
/**
 * Create an Observer for the event type on this group
 * @param eventType
 */
entitas.Group.prototype.createObserver = function (eventType) {
  if (eventType === undefined)
    eventType = GroupEventType.OnEntityAdded;
  return new entitas.GroupObserver(this, eventType);
};
/**
 * Handle adding and removing component from the entity without raising events
 * @param entity
 */
entitas.Group.prototype.handleEntitySilently = function (entity) {
  if (this._matcher.matches(entity)) {
    this.addEntitySilently(entity);
  }
  else {
    this.removeEntitySilently(entity);
  }
};
/**
 * Handle adding and removing component from the entity and raisieevents
 * @param entity
 * @param index
 * @param component
 */
entitas.Group.prototype.handleEntity = function (entity, index, component) {
  if (this._matcher.matches(entity)) {
    this.addEntity(entity, index, component);
  }
  else {
    this.removeEntity(entity, index, component);
  }
};
/**
 * Update entity and raise events
 * @param entity
 * @param index
 * @param previousComponent
 * @param newComponent
 */
entitas.Group.prototype.updateEntity = function (entity, index, previousComponent, newComponent) {
  if (entity.id in this._entities) {
    var onEntityRemoved = this.onEntityRemoved;
    if (onEntityRemoved.active)
      onEntityRemoved.dispatch(this, entity, index, previousComponent);
    var onEntityAdded = this.onEntityAdded;
    if (onEntityAdded.active)
      onEntityAdded.dispatch(this, entity, index, newComponent);
    var onEntityUpdated = this.onEntityUpdated;
    if (onEntityUpdated.active)
      onEntityUpdated.dispatch(this, entity, index, previousComponent, newComponent);
  }
};
/**
 * Add entity without raising events
 * @param entity
 */
entitas.Group.prototype.addEntitySilently = function (entity) {
  if (!(entity.id in this._entities)) {
    this._entities[entity.id] = entity;
    this._entitiesCache = null;
    this._singleEntityCache = null;
    entity.addRef();
  }
};
/**
 * Add entity and raise events
 * @param entity
 * @param index
 * @param component
 */
entitas.Group.prototype.addEntity = function (entity, index, component) {
  if (!(entity.id in this._entities)) {
    this._entities[entity.id] = entity;
    this._entitiesCache = null;
    this._singleEntityCache = null;
    entity.addRef();
    var onEntityAdded = this.onEntityAdded;
    if (onEntityAdded.active)
      onEntityAdded.dispatch(this, entity, index, component);
  }
};
/**
 * Remove entity without raising events
 * @param entity
 */
entitas.Group.prototype.removeEntitySilently = function (entity) {
  if (entity.id in this._entities) {
    delete this._entities[entity.id];
    this._entitiesCache = null;
    this._singleEntityCache = null;
    entity.release();
  }
};
/**
 * Remove entity and raise events
 * @param entity
 * @param index
 * @param component
 */
entitas.Group.prototype.removeEntity = function (entity, index, component) {
  if (entity.id in this._entities) {
    delete this._entities[entity.id];
    this._entitiesCache = null;
    this._singleEntityCache = null;
    var onEntityRemoved = this.onEntityRemoved;
    if (onEntityRemoved.active)
      onEntityRemoved.dispatch(this, entity, index, component);
    entity.release();
  }
};
/**
 * Check if group has this entity
 *
 * @param entity
 * @returns boolean
 */
entitas.Group.prototype.containsEntity = function (entity) {
  return entity.id in this._entities;
};
/**
 * Get a list of the entities in this group
 *
 * @returns Array<entitas.Entity>
 */
entitas.Group.prototype.getEntities = function () {
  if (this._entitiesCache == null) {
    var entities = this._entities;
    var keys = Object.keys(entities);
    var length = keys.length;
    var entitiesCache = this._entitiesCache = new Array(length);
    for (var i = 0; i < length; i++) {
      entitiesCache[i] = entities[keys[i]];
    }
  }
  return this._entitiesCache;
};
/**
 * Gets an entity singleton.
 * If a group has more than 1 entity, this is an error condition.
 *
 * @returns entitas.Entity
 */
entitas.Group.prototype.getSingleEntity = function () {
  if (this._singleEntityCache == null) {
    var enumerator = Object.keys(this._entities);
    var c = enumerator.length;
    if (c === 1) {
      this._singleEntityCache = this._entities[enumerator[0]];
    }
    else if (c === 0) {
      return null;
    }
    else {
      throw new entitas.exceptions.SingleEntityException(this._matcher);
    }
  }
  return this._singleEntityCache;
};
/**
 * Create a string representation for this group:
 *
 * ex: 'Group(Position)'
 *
 * @returns string
 */
entitas.Group.prototype.toString = function () {
  if (this._toStringCache == null) {
    this._toStringCache = "Group(" + this._matcher + ")";
  }
  return this._toStringCache;
};