Source: Matcher.js

goog.provide('entitas.Matcher');
goog.require('entitas.exceptions.MatcherException');
goog.require('entitas.TriggerOnEvent');
goog.require('entitas.GroupEventType');


/**
 * @constructor
 *
 */
entitas.Matcher = function() {
  this._id = Matcher.uniqueId++;
}
Object.defineProperty(entitas.Matcher.prototype, "id", {
  /**
   * Get the matcher id
   * @type {number}
   * @name entitas.Matcher#id */
  get: function () { return this._id; },
  enumerable: true,
  configurable: true
});
Object.defineProperty(entitas.Matcher.prototype, "indices", {
  /**
   * A list of the component ordinals that this matches
   * @type {Array<number>}
   * @name entitas.Matcher#indices */
  get: function () {
    if (!this._indices) {
      this._indices = this.mergeIndices();
    }
    return this._indices;
  },
  enumerable: true,
  configurable: true
});
Object.defineProperty(entitas.Matcher.prototype, "allOfIndices", {
  /**
   * A unique sequential index number assigned to each entity at creation
   * @type {number}
   * @name entitas.Matcher#allOfIndices */
  get: function () { return this._allOfIndices; },
  enumerable: true,
  configurable: true
});
Object.defineProperty(entitas.Matcher.prototype, "anyOfIndices", {
  /**
   * A unique sequential index number assigned to each entity at creation
   * @type {number}
   * @name entitas.Matcher#anyOfIndices */
  get: function () { return this._anyOfIndices; },
  enumerable: true,
  configurable: true
});
Object.defineProperty(entitas.Matcher.prototype, "noneOfIndices", {
  /**
   * A unique sequential index number assigned to each entity at creation
   * @type {number}
   * @name entitas.Matcher#noneOfIndices */
  get: function () { return this._noneOfIndices; },
  enumerable: true,
  configurable: true
});
/**
 * Matches anyOf the components/indices specified
 * @params {Array<entitas.IMatcher>|Array<number>} args
 * @returns {entitas.Matcher}
 */
entitas.Matcher.prototype.anyOf = function () {
  var args = [];
  for (var _i = 0; _i < arguments.length; _i++) {
    args[_i - 0] = arguments[_i];
  }
  if ('number' === typeof args[0] || 'string' === typeof args[0]) {
    this._anyOfIndices = Matcher.distinctIndices(args);
    this._indices = null;
    return this;
  }
  else {
    return this.anyOf.apply(this, Matcher.mergeIndices(args));
  }
};
/**
 * Matches noneOf the components/indices specified
 * @params {Array<entitas.IMatcher>|Array<number>} args
 * @returns {entitas.Matcher}
 */
entitas.Matcher.prototype.noneOf = function () {
  var args = [];
  for (var _i = 0; _i < arguments.length; _i++) {
    args[_i - 0] = arguments[_i];
  }
  if ('number' === typeof args[0] || 'string' === typeof args[0]) {
    this._noneOfIndices = Matcher.distinctIndices(args);
    this._indices = null;
    return this;
  }
  else {
    return this.noneOf.apply(this, Matcher.mergeIndices(args));
  }
};
/**
 * Check if the entity matches this matcher
 * @param {entitas.Entity} entity
 * @returns {boolean}
 */
entitas.Matcher.prototype.matches = function (entity) {
  var matchesAllOf = this._allOfIndices == null ? true : entity.hasComponents(this._allOfIndices);
  var matchesAnyOf = this._anyOfIndices == null ? true : entity.hasAnyComponent(this._anyOfIndices);
  var matchesNoneOf = this._noneOfIndices == null ? true : !entity.hasAnyComponent(this._noneOfIndices);
  return matchesAllOf && matchesAnyOf && matchesNoneOf;
};
/**
 * Merge list of component indices
 * @returns {Array<number>}
 */
entitas.Matcher.prototype.mergeIndices = function () {
  //var totalIndices = (this._allOfIndices != null ? this._allOfIndices.length : 0)
  // + (this._anyOfIndices != null ? this._anyOfIndices.length : 0)
  // + (this._noneOfIndices != null ? this._noneOfIndices.length : 0);
  var indicesList = [];
  if (this._allOfIndices != null) {
    indicesList = indicesList.concat(this._allOfIndices);
  }
  if (this._anyOfIndices != null) {
    indicesList = indicesList.concat(this._anyOfIndices);
  }
  if (this._noneOfIndices != null) {
    indicesList = indicesList.concat(this._noneOfIndices);
  }
  return Matcher.distinctIndices(indicesList);
};
/**
 * toString representation of this matcher
 * @returns {string}
 */
entitas.Matcher.prototype.toString = function () {
  if (this._toStringCache == null) {
    var sb = [];
    if (this._allOfIndices != null) {
      Matcher.appendIndices(sb, "AllOf", this._allOfIndices);
    }
    if (this._anyOfIndices != null) {
      if (this._allOfIndices != null) {
        sb[sb.length] = '.';
      }
      Matcher.appendIndices(sb, "AnyOf", this._anyOfIndices);
    }
    if (this._noneOfIndices != null) {
      Matcher.appendIndices(sb, ".NoneOf", this._noneOfIndices);
    }
    this._toStringCache = sb.join('');
  }
  return this._toStringCache;
};
// /**
// * Check if the matchers are equal
// * @param {Object} obj
// * @returns {boolean}
// */
// public equals(obj) {
//  if (obj == null || obj == null) return false;
//  var matcher:Matcher = obj;
//  if (!Matcher.equalIndices(matcher.allOfIndices, this._allOfIndices)) {
//   return false;
//  }
//  if (!Matcher.equalIndices(matcher.anyOfIndices, this._anyOfIndices)) {
//   return false;
//  }
//  if (!Matcher.equalIndices(matcher.noneOfIndices, this._noneOfIndices)) {
//   return false;
//  }
//  return true;
// }
// /**
// * Check if the lists of component indices are equal
// * @param {Array<number>} list1
// * @param {Array<number>} list2
// * @returns {boolean}
// */
// public static equalIndices(i1:number[], i2:number[]):boolean {
//  if ((i1 == null) != (i2 == null)) {
//   return false;
//  }
//  if (i1 == null) {
//   return true;
//  }
//  if (i1.length !== i2.length) {
//   return false;
//  }
//  for (var i = 0, indicesLength = i1.length; i < indicesLength; i++) {
//   /** compare coerced values so we can compare string type to number type */
//   if (i1[i] != i2[i]) {
//    return false;
//   }
//  }
//  return true;
// }
/**
 * Get the set if distinct (non-duplicate) indices from a list
 * @param {Array<number>} indices
 * @returns {Array<number>}
 */
Matcher.distinctIndices = function (indices) {
  var indicesSet = {};
  for (var i = 0, l = indices.length; i < l; i++) {
    var k = '' + indices[i];
    indicesSet[k] = i;
  }
  return [].concat(Object.keys(indicesSet));
};
/**
 * Merge all the indices of a set of Matchers
 * @param {Array<IMatcher>} matchers
 * @returns {Array<number>}
 */
Matcher.mergeIndices = function (matchers) {
  var indices = [];
  for (var i = 0, matchersLength = matchers.length; i < matchersLength; i++) {
    var matcher = matchers[i];
    if (matcher.indices.length !== 1) {
      throw new entitas.exceptions.MatcherException(matcher);
    }
    indices[i] = matcher.indices[0];
  }
  return indices;
};
/**
 * Matches allOf the components/indices specified
 * @params {Array<entitas.IMatcher>|Array<number>} args
 * @returns {entitas.Matcher}
 */
Matcher.allOf = function () {
  var args = [];
  for (var _i = 0; _i < arguments.length; _i++) {
    args[_i - 0] = arguments[_i];
  }
  if ('number' === typeof args[0] || 'string' === typeof args[0]) {
    var matcher = new Matcher();
    var indices = matcher._allOfIndices = Matcher.distinctIndices(args);
    return matcher;
  }
  else {
    return Matcher.allOf.apply(this, Matcher.mergeIndices(args));
  }
};
/**
 * Matches anyOf the components/indices specified
 * @params {Array<entitas.IMatcher>|Array<number>} args
 * @returns {entitas.Matcher}
 */
Matcher.anyOf = function () {
  var args = [];
  for (var _i = 0; _i < arguments.length; _i++) {
    args[_i - 0] = arguments[_i];
  }
  if ('number' === typeof args[0] || 'string' === typeof args[0]) {
    var matcher = new Matcher();
    var indices = matcher._anyOfIndices = Matcher.distinctIndices(args);
    return matcher;
  }
  else {
    return Matcher.anyOf.apply(this, Matcher.mergeIndices(args));
  }
};
Matcher.appendIndices = function (sb, prefix, indexArray) {
  var SEPERATOR = ", ";
  var j = sb.length;
  sb[j++] = prefix;
  sb[j++] = '(';
  var lastSeperator = indexArray.length - 1;
  for (var i = 0, indicesLength = indexArray.length; i < indicesLength; i++) {
    sb[j++] = '' + indexArray[i];
    if (i < lastSeperator) {
      sb[j++] = SEPERATOR;
    }
  }
  sb[j++] = ')';
};
/**
 * Subscribe to Entity Added event
 * @returns {entitas.TriggerOnEvent}
 */
entitas.Matcher.prototype.onEntityAdded = function () {
  return new entitas.TriggerOnEvent(this, GroupEventType.OnEntityAdded);
};
/**
 * Subscribe to Entity Removed event
 * @returns {entitas.TriggerOnEvent}
 */
entitas.Matcher.prototype.onEntityRemoved = function () {
  return new entitas.TriggerOnEvent(this, GroupEventType.OnEntityRemoved);
};
/**
 * Subscribe to Entity Added or Removed event
 * @returns {entitas.TriggerOnEvent}
 */
entitas.Matcher.prototype.onEntityAddedOrRemoved = function () {
  return new entitas.TriggerOnEvent(this, GroupEventType.OnEntityAddedOrRemoved);
};
/**
 * A unique sequential index number assigned to each ,atch
 * @type {number} */
Matcher.uniqueId = 0;