UNPKG

thingmodel

Version:

Synchronize data and models across multiple devices

173 lines (139 loc) 4.67 kB
module ThingModel { export class Warehouse { private _thingTypes: { [key: string]: ThingType }; private _things: { [key: string]: Thing }; private _observers: IWarehouseObserver[]; constructor() { this._thingTypes = {}; this._things = {}; this._observers = []; } public RegisterType(type: ThingType, force: boolean = true, sender: string=null): void { if (!type) { throw new Error("The thing type information is null."); } if (force || !_.has(this._thingTypes, type.Name)) { this._thingTypes[type.Name] = type; this.NotifyThingTypeDefine(type, sender); } } public RegisterThing(thing: Thing, alsoRegisterConnections: boolean = true, alsoRegisterTypes: boolean = true, sender: string=null): void { if (!thing) { throw new Error("A thing should not be null if it want to be allowed in the warehouse"); } var creation = !_.has(this._things, thing.ID); this._things[thing.ID] = thing; if (alsoRegisterTypes && thing.Type) { this.RegisterType(thing.Type, false, sender); } if (alsoRegisterConnections) { var alreadyVisitedObjects: { [id: string]: boolean } = {}; _.each(thing.ConnectedThings, (connectedThing) => { this.RecursiveRegisterThing(connectedThing, alsoRegisterTypes, alreadyVisitedObjects, sender); }); } if (creation) { this.NotifyThingCreation(thing, sender); } else { this.NotifyThingUpdate(thing, sender); } } private RecursiveRegisterThing(thing: Thing, alsoRegisterTypes: boolean, alreadyVisitedObjects: { [id: string]: boolean }, sender: string): void { // Avoid infinite recursions if (alreadyVisitedObjects.hasOwnProperty(thing.ID)) { return; } alreadyVisitedObjects[thing.ID] = true; this.RegisterThing(thing, false, alsoRegisterTypes, sender); _.each(thing.ConnectedThings, (connectedThing) => { this.RecursiveRegisterThing(connectedThing, alsoRegisterTypes, alreadyVisitedObjects, sender); }); } public RegisterCollection(collection: Thing[], alsoRegisterTypes: boolean=true, sender: string=null): void { var alreadyVisitedObjects: { [id: string]: boolean } = {}; _.each(collection, (thing) => { this.RecursiveRegisterThing(thing, alsoRegisterTypes, alreadyVisitedObjects, sender); }); } public RemoveCollection(collection: { [id: string]: Thing }, notifyUpdates = true, sender: string=null) { var thingsToDisconnect: { [id: string]: Thing } = {}; _.each(_.keys(collection), (id: string) => { var thing = collection[id]; if (notifyUpdates) { _.each(this._things, (t: Thing) => { if (t.IsConnectedTo(thing)) { thingsToDisconnect[t.ID] = t; } }); } this.RemoveThing(thing, false, sender); }); if (notifyUpdates) { _.each(_.keys(thingsToDisconnect), (id: string) => { if (!collection.hasOwnProperty(id)) { this.NotifyThingUpdate(thingsToDisconnect[id]); } }); } } public RemoveThing(thing: Thing, notifyUpdates = true, sender: string=null): void { if (!thing) { return; } // Remove all connections _.each(this._things, (t: Thing) => { if (t.IsConnectedTo(thing)) { t.Disconnect(thing); if (notifyUpdates) { this.NotifyThingUpdate(t, sender); } } }); if (_.has(this._things, thing.ID)) { delete this._things[thing.ID]; this.NotifyThingDeleted(thing, sender); } } public RegisterObserver(observer: IWarehouseObserver): void { this._observers.push(observer); } public UnregisterObserver(observer: IWarehouseObserver): void { // Array remove this._observers.splice(_.indexOf(this._observers, observer), 1); } public NotifyThingTypeDefine(type: ThingType, sender: string=null): void { _.each(this._observers, (observer) => { observer.Define(type, sender); }); } public NotifyThingUpdate(thing: Thing, sender: string=null): void { _.each(this._observers, (observer) => { observer.Updated(thing, sender); }); } public NotifyThingCreation(thing: Thing, sender: string=null): void { _.each(this._observers, (observer) => { observer.New(thing, sender); }); } public NotifyThingDeleted(thing: Thing, sender: string= null): void { _.each(this._observers, (observer) => { observer.Deleted(thing, sender); }); } public GetThing(id: string): Thing { return this._things[id]; } public GetThingType(name: string): ThingType { return this._thingTypes[name]; } public get Things(): Thing[] { return _.values(this._things); } public get ThingsTypes(): ThingType[] { return _.values(this._thingTypes); } } }