module entitas { "use strict" ; import Entity = entitas . Entity ; import Component = entitas . IComponent ; import IAllOfMatcher = entitas . IAllOfMatcher ; import IAnyOfMatcher = entitas . IAnyOfMatcher ; import INoneOfMatcher = entitas . INoneOfMatcher ; import MatcherException = entitas . exceptions . MatcherException ; import GroupObserver = entitas . GroupObserver ; import TriggerOnEvent = entitas . TriggerOnEvent ; readonly enum { number } export enum GroupEventType { OnEntityAdded , OnEntityRemoved , OnEntityAddedOrRemoved } export module Matcher { } export class Matcher implements IAllOfMatcher , IAnyOfMatcher , INoneOfMatcher { type { number } name public get id ( ) : number { return this . _id ; } type { number } public static uniqueId : number = 0 ; type { Array < number > } name public get indices ( ) : number [ ] { if ( ! this . _indices ) { this . _indices = this . mergeIndices ( ) ; } return this . _indices ; } type { number } name public get allOfIndices ( ) : number [ ] { return this . _allOfIndices ; } type { number } name public get anyOfIndices ( ) : number [ ] { return this . _anyOfIndices ; } type { number } name public get noneOfIndices ( ) : number [ ] { return this . _noneOfIndices ; } private _indices : number [ ] ; public _allOfIndices : number [ ] ; public _anyOfIndices : number [ ] ; public _noneOfIndices : number [ ] ; private _toStringCache : string ; private _id : number ; /** Extension Points */ constructor constructor ( ) { this . _id = Matcher . uniqueId ++ ; } public anyOf ( ... args ) ; public anyOf ( ... args ) ; params returns { entitas . Matcher } public anyOf ( ... args ) { 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 ) ) ; } } public noneOf ( ... args ) ; public noneOf ( ... args ) ; params returns { entitas . Matcher } public noneOf ( ... args ) { 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 ) ) ; } } param { entitas . Entity } entity returns { boolean } public matches ( entity ) { const matchesAllOf = this . _allOfIndices == null ? true : entity . hasComponents ( this . _allOfIndices ) ; const matchesAnyOf = this . _anyOfIndices == null ? true : entity . hasAnyComponent ( this . _anyOfIndices ) ; const matchesNoneOf = this . _noneOfIndices == null ? true : ! entity . hasAnyComponent ( this . _noneOfIndices ) ; return matchesAllOf && matchesAnyOf && matchesNoneOf ; } returns { Array < number > } public mergeIndices ( ) { let 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 ) ; } returns { string } public toString ( ) { if ( this . _toStringCache == null ) { const 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 ; } param { Array < number > } indices returns { Array < number > } public static distinctIndices ( indices ) { const indicesSet = { } ; for ( let i = 0 , l = indices . length ; i < l ; i ++ ) { const k = '' + indices [ i ] ; indicesSet [ k ] = i ; } return [ ] . concat ( Object . keys ( indicesSet ) ) ; } param { Array < IMatcher > } matchers returns { Array < number > } public static mergeIndices ( matchers ) { const indices = [ ] ; for ( let i = 0 , matchersLength = matchers . length ; i < matchersLength ; i ++ ) { const matcher = matchers [ i ] ; if ( matcher . indices . length !== 1 ) { throw new MatcherException ( matcher ) ; } indices [ i ] = matcher . indices [ 0 ] ; } return indices ; } public static allOf ( ... args ) ; public static allOf ( ... args ) ; params returns { entitas . Matcher } public static allOf ( ... args ) { if ( 'number' === typeof args [ 0 ] || 'string' === typeof args [ 0 ] ) { const matcher = new Matcher ( ) ; const indices = matcher . _allOfIndices = Matcher . distinctIndices ( args ) ; return matcher ; } else { return Matcher . allOf . apply ( this , Matcher . mergeIndices ( args ) ) ; } } public static anyOf ( ... args ) ; public static anyOf ( ... args ) ; params returns { entitas . Matcher } public static anyOf ( ... args ) { if ( 'number' === typeof args [ 0 ] || 'string' === typeof args [ 0 ] ) { const matcher = new Matcher ( ) ; const indices = matcher . _anyOfIndices = Matcher . distinctIndices ( args ) ; return matcher ; } else { return Matcher . anyOf . apply ( this , Matcher . mergeIndices ( args ) ) ; } } private static appendIndices ( sb , prefix , indexArray ) { const SEPERATOR = ", " ; let j = sb . length ; sb [ j ++ ] = prefix ; sb [ j ++ ] = '(' ; const lastSeperator = indexArray . length - 1 ; for ( let i = 0 , indicesLength = indexArray . length ; i < indicesLength ; i ++ ) { sb [ j ++ ] = '' + indexArray [ i ] ; if ( i < lastSeperator ) { sb [ j ++ ] = SEPERATOR ; } } sb [ j ++ ] = ')' ; } returns { entitas . TriggerOnEvent } public onEntityAdded ( ) { return new TriggerOnEvent ( this , GroupEventType . OnEntityAdded ) ; } returns { entitas . TriggerOnEvent } public onEntityRemoved ( ) { return new TriggerOnEvent ( this , GroupEventType . OnEntityRemoved ) ; } returns { entitas . TriggerOnEvent } public onEntityAddedOrRemoved ( ) { return new TriggerOnEvent ( this , GroupEventType . OnEntityAddedOrRemoved ) ; } } }