import DataCollectionChangeListener = require('./DataCollectionChangeListener') import DataCollectionChangeProvider = require('./DataCollectionChangeProvider') import DataCollectionConfig = require('./DataCollectionConfig') import DataModel = require('./DataModel') import FilterRule = require('./FilterRule') import FilterCollection = require('./FilterCollection'); import DataProvider = require('./DataProvider'); class DataCollection implements DataCollectionChangeListener, DataCollectionChangeProvider { private static INSTANCE_COUNTER = 0 protected allEntities:T[] = new Array() protected filteredEntities:T[] = new Array() private filters:FilterCollection = new FilterCollection() private changeProvider:DataCollectionChangeProvider protected dataProvider:DataProvider private scopeName:string private changeListeners:Array> = new Array() private instanceNr:number constructor(config:DataCollectionConfig) { this.instanceNr = ++DataCollection.INSTANCE_COUNTER this.scopeName = config.scope this.dataProvider = config.dataProvider this.changeProvider = config.changeProvider config.changeProvider.addChangeListener(this) if (config.filter) { this.addFilter(config.filter) } if (config.changeListener) { this.addChangeListener(config.changeListener) } this.storeEntitiesAndApplyFilters(config.initialEntities) } protected storeEntitiesAndApplyFilters(entities:DataModel[], forceTriggerChildren?:boolean) { this.allEntities = entities || new Array() this.applyFilters(forceTriggerChildren ? 'force' : 'normal') } dataCollectionChanged(dataCollection:DataCollection, forceTriggerChildren?:boolean) { this.storeEntitiesAndApplyFilters(dataCollection.filteredEntities, forceTriggerChildren) } public find(searchMap:{[s:string]: Object}|string):T { let entity:T = null let shouldCompareByIdentityHashCode = typeof searchMap == 'string' let mapAsMap = searchMap as {[s:string]: Object} this.filteredEntities.some((currentEntity:T) => { let shouldUseEntity = true if (shouldCompareByIdentityHashCode) { shouldUseEntity = currentEntity.computeIdentityHashCode() == searchMap } else { Object.keys(searchMap).some((key) => { shouldUseEntity = shouldUseEntity && (currentEntity.getPropertyForFilter(key) == mapAsMap[key]) return !shouldUseEntity }) } if (shouldUseEntity) { entity = currentEntity return true } return false }) return entity } protected applyFilters(applyFilterMode:ApplyFilterMode):boolean { let filteredEntities:T[] = this.filters.runFilters(this.allEntities) let somethingChanged =  applyFilterMode == 'force' || this.filteredEntitiesChanged(filteredEntities) this.filteredEntities = filteredEntities if (somethingChanged && applyFilterMode != 'skip') { this.triggerListeners() } return somethingChanged } private filteredEntitiesChanged(newFilteredEntities:DataModel[]):boolean { if (this.filteredEntities.length != newFilteredEntities.length) { return true } let lookupMap:{[s:string]: boolean} = {} this.filteredEntities.forEach((dataModel:DataModel) => { lookupMap[dataModel.computeIdentityHashCode()] = false }) let entitiesChanged = false newFilteredEntities.some((dataModel:DataModel) => { let identiyHashCode = dataModel.computeIdentityHashCode() if (lookupMap.hasOwnProperty(identiyHashCode)) { delete lookupMap[identiyHashCode] return false } else { entitiesChanged = true return true } }) return entitiesChanged } public getInstanceNr() { return this.instanceNr } public getEntities():T[] { return this.filteredEntities.slice(0) } isEmpty():boolean { return this.filteredEntities.length === 0 } getFirstEntity():T { if (this.isEmpty()) { return null } return this.filteredEntities[0] } getLastEntity():T { if (this.isEmpty()) { return null } return this.filteredEntities[this.filteredEntities.length - 1] } public addFilter(filter:FilterRule|FilterRule[]):boolean { this.filters.addFilter(filter) this.dataProvider.filtersChanged(this.scopeName, this.filters) return this.applyFilters('normal') } public setFilter(filter:FilterRule|FilterRule[]):boolean { this.filters.setFilter(filter) this.dataProvider.filtersChanged(this.scopeName, this.filters) return this.applyFilters('normal') } public createCopy():DataCollection { return new DataCollection({ dataProvider: this.dataProvider, changeProvider: this.changeProvider, initialEntities: this.allEntities, filter: this.filters.getFilterRules(), scope: this.scopeName}) } public createSubCollection(filter:FilterRule|FilterRule[]):DataCollection { return new DataCollection({ dataProvider: this.dataProvider, changeProvider: this, initialEntities: this.filteredEntities, filter: filter, scope: this.scopeName}) } public getFilteredDataModels() { return this.filteredEntities } protected triggerListeners(forceTriggerChildren?:boolean) { // console.log('DataCollection - trigger listeners', this.instanceNr, forceTriggerChildren) this.changeListeners.forEach((listener) => { listener.dataCollectionChanged(this, forceTriggerChildren) }) } public addChangeListener(listener:DataCollectionChangeListener) { this.changeListeners.push(listener) } public removeChangeListener(listener:DataCollectionChangeListener) { let index = this.changeListeners.indexOf(listener) if (index > -1) { this.changeListeners.splice(index, 1 ); } } } export = DataCollection