Skip to content
Snippets Groups Projects
aggregator.js 26.9 KiB
Newer Older
Stefanie Lemcke's avatar
Stefanie Lemcke committed
/**
 * This module representing a Context Aggregator. 
 * It aggregates data from multiple widgets.
 * 
 * @module Aggregator
 * @fileOverview
 */
define(['easejs', 'MathUuid','widget',
        'attribute', 'attributeList', 'subscriber',
        'subscriberList', 'callbackList', 'storage', 'interpreter', 'interpretation'],
 	function(easejs, MathUuid, Widget, Attribute,
 			AttributeList, Subscriber, SubscriberList,
 			CallbackList, Storage, Interpreter, Interpretation){
Stefanie Lemcke's avatar
Stefanie Lemcke committed

 	var Class = easejs.Class;
	var Aggregator =  Class('Aggregator').
Stefanie Lemcke's avatar
Stefanie Lemcke committed
				extend(Widget, 
			
	{
	   /**
	    * @alias name
	    * @public
	    * @type {string}
	    * @memberof Aggregator#
	    * @desc Name of the Widget.
        */
		'public name' : 'Aggregator',
		
		/**
		 * @alias id
		 * @public
		 * @type {string}
		 * @memberof Aggregator#
		 * @desc ID of the Aggregator. Will be generated.
		 */
		'public id' : '', 
		
		/**
		 * @alias widgets
		 * @protected
		 * @type {Array}
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * @memberof Aggregator#
		 * @desc List of subscribed widgets referenced by ID.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 */
		'protected widgets' : [],
Tobias Moebert's avatar
Tobias Moebert committed

		/**
		 * @type {Array.<Interpretation>}
		 */
		'protected interpretations' : [],
Tobias Moebert's avatar
Tobias Moebert committed

Stefanie Lemcke's avatar
Stefanie Lemcke committed
		/**
		 * @alias db
		 * @protected
		 * @type {Storage}
		 * @memberof Aggregator#
		 * @desc Database of the Aggregator.
		 */
		'protected db' : '',
		
		/**
		 * Constructor: Generates the id and initializes the Aggregator.
		 * 
		 * @abstract
		 * @class Aggregator
		 * @extends Widget
		 * @classdesc The Widget handles the access to sensors.
		 * @requires easejs
		 * @requires MathUuid
		 * @requires CallbackList
		 * @requires Attribute
		 * @requires AttributeList
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * @requires Subscriber
		 * @requires SubscriberList
		 * @requires Storage
		 * @requires Widget
		 * @constructs Aggregator
		 */
		'override virtual public __construct': function(_discoverer, _attributes)
Stefanie Lemcke's avatar
Stefanie Lemcke committed
        {
			this.id = Math.uuid();
			this.widgets = [];
            this.interpretations = [];
			this.__super(_discoverer, _attributes);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
        },
        
        /**
		 * Returns the type of this class, in this case
		 * "Aggregator".
		 * 
		 * @override
		 * @public
		 * @alias getType
		 * @memberof Aggregator#
		 * @returns {string}
		 */
		'override public getType' : function(){
		    return 'Aggregator';
		 },
		
		/**
		 * Sets Widget IDs.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * 
		 * @protected
	   	 * @alias setWidgets
		 * @memberof Aggregator#
		 * @param {Array} _widgetIds List of Widget IDs
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'protected setWidgets' : function(_widgetIds){
			this.widgets = _widgetIds;
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Adds Widget ID.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * 
		 * @public
	   	 * @alias addWidget
		 * @memberof Aggregator#
		 * @param {String|Widget} _widgetIdOrWidget Widget ID
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'public addWidget' : function(_widgetIdOrWidget){
            if (Class.isA(Widget, _widgetIdOrWidget)) {
                this.widgets.push(_widgetIdOrWidget.getId());
            } else if(typeof _widgetIdOrWidget == "string") {
                this.widgets.push(_widgetIdOrWidget);
            }
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Returns the available Widget IDs.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * 
		 * @public
		 * @alias getWidgets
		 * @memberof Aggregator#
		 * @returns {Array}
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 */
		'public getWidgets' : function() {
			return this.widgets;
		},
		
		/**
		 * Removes Widget ID from list.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * 
		 * @protected
	   	 * @alias removeWidget
		 * @memberof Aggregator#
		 * @param {String} _widgetId Id of the Widget
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'protected removeWidget' : function(_widgetId){
            var index = this.widgets.indexOf(_widgetId);
            if (index > -1) {
                this.widgets = this.widgets.splice(index, 1);
            }
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Retrieves all Attributes of the specified widgets.
		 * 
		 * @protected
	   	 * @alias initAttributes
		 * @memberof Aggregator#
	     */
		'protected initOutAttributes' : function(){
			if(this.widgets.length > 0){
				var widgetIdList = this.widgets;
				for(var i in widgetIdList){
					var widgetId = widgetIdList[i];
					var widgetInstance = this.discoverer.getComponent(widgetId);
					if (widgetInstance) {
						this.setOutAttributes(widgetInstance.queryAttributes());
Stefanie Lemcke's avatar
Stefanie Lemcke committed
					}
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Retrieves all ConstantAttributes of the specified widgets.
		 * 
		 * @protected
	   	 * @alias initConstantAttributes
		 * @memberof Aggregator#
	     */
		'protected initConstantOutAttributes' : function(){
			if(this.widgets.length > 0){
                var widgetIdList = this.widgets;
				for(var i in widgetIdList){
					var widgetId = widgetIdList[i];
					var widgetInstance = this.discoverer.getComponent(widgetId);
					if (widgetInstance) {
Stefanie Lemcke's avatar
Stefanie Lemcke committed
						this.setConstantAttributes(widgetInstance.queryConstantAttributes());
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Retrieves all actual Callbacks of the specified Widgets.
		 * 
		 * @protected
	   	 * @alias initCallbacks
		 * @memberof Aggregator#
	     */
		'protected initCallbacks' : function(){
			if(this.widgets.length > 0){
				var widgetIdList = this.widgets;
				for(var i in widgetIdList){
					var widgetId = widgetIdList[i];
					this.initWidgetSubscription(widgetId);

		/**
		 * Start the setup of the aggregator after the initialisation has finished.
		 *
		 * @public
		 * @alias didFinishInitialization
		 * @memberof Aggregator#
        'override public didFinishInitialization': function(_attributes) {
            this.aggregatorSetup(_attributes);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * InitMethod for Aggregators. Called by constructor.
		 * Initializes the associated Storage.
		 * 
		 * @protected
	   	 * @alias aggregatorSetup
		 * @memberof Aggregator#
	     */
		'protected aggregatorSetup' : function(_attributes){
			this.initStorage('DB_'+this.name);
			this.setAggregatorAttributeValues(_attributes);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
			this.setAggregatorConstantAttributeValues();
			this.setAggregatorCallbacks();

            this.didFinishSetup();
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Initializes the provided attributeValues that are only specific to the Aggregator.
		 * Called by aggregatorSetup().
		 * 
		 * @function
		 * @abstract
		 * @protected
		 * @alias setAggregatorAttributeValues
		 * @memberof Aggregator#
		 */
		'virtual protected setAggregatorAttributeValues' : function(_attributes) {
            for (var index in _attributes) {
                var theAttribute = _attributes[index];
                this.addOutAttribute(theAttribute);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		/**
		 * Initializes the provided ConstantAttributeValues that are only specific to the Aggregator.
		 * Called by aggregatorSetup().
		 * 
		 * @function
		 * @abstract
		 * @protected
		 * @alias setAggregatorConstantAttributeValues
		 * @memberof Aggregator#
		 */
		'virtual protected setAggregatorConstantAttributeValues' : function() {

        },

Stefanie Lemcke's avatar
Stefanie Lemcke committed
		/**
		 * Initializes the provided Callbacks that are only specific to the Aggregator.
		 * Called by aggregatorSetup().
		 * 
		 * @function
		 * @abstract
		 * @protected
		 * @alias setAggregatorCallbacks
		 * @memberof Aggregator#
		 */
		'virtual protected setAggregatorCallbacks' : function() {

        },
Stefanie Lemcke's avatar
Stefanie Lemcke committed

		/**
		 * Returns the current Attributes that are saved in the cache.
		 * 
		 * @public
	   	 * @alias getCurrentData
		 * @memberof Aggregator#
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'public getCurrentData' : function(){
			return this.outAttributes;
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Subscribes to the given widget for the specified Callbacks.
		 * 
		 * @protected
	   	 * @alias subscribeTo
		 * @memberof Aggregator#
		 * @param {Widget} _widget Widget that should be subscribed to.
		 * @param {CallbackList} _callbacks required Callbacks
	     */
		'protected subscribeTo' : function(_widget, _callbacks, _subSet, _conditions){	
			if(Class.isA(Widget, _widget)){
				var subscriber = new Subscriber().withSubscriberId(this.id).
									withSubscriberName(this.name).
									withSubscriptionCallbacks(_callbacks).
									withAttributesSubset(_subSet).
									withConditions(_conditions);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
				_widget.addSubscriber(subscriber);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Subscribes to the widgets that are defined in the Widget ID List
Stefanie Lemcke's avatar
Stefanie Lemcke committed
         * used in the initCallback method.
		 * 
		 * @protected
	   	 * @alias initWidgetSubscription
		 * @memberof Aggregator#
		 * @param {String} _widgetId Widget that should be subscribed.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * @returns {?CallbackList}
	     */
		'protected initWidgetSubscription' : function(_widgetId){
Stefanie Lemcke's avatar
Stefanie Lemcke committed
			var calls = null;
			if(Class.isA(String, _widgetId)){
				var widget = this.discoverer.getComponent(_widgetId);
				if (widget){
Stefanie Lemcke's avatar
Stefanie Lemcke committed
					//subscribe to all callbacks
					calls = widget.queryCallbacks();
					this.subscribeTo(widget, calls);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		},
		
		/**
		 * Adds the specified callbacks of a widget to the aggregator.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
         * 
		 * @public
	   	 * @alias addWidgetSubscription
		 * @memberof Aggregator#
		 * @param {String|Widget} _widgetIdOrWidget Widget that should be subscribed.
		 * @param {CallbackList} _callbackList required Callbacks
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'public addWidgetSubscription' : function(_widgetIdOrWidget, _callbackList){
            if (Class.isA(Widget, _widgetIdOrWidget)) {
                if (Class.isA(Widget, _widgetIdOrWidget) && (!_callbackList || !Class.isA(CallbackList, _callbackList))) {
                    _callbackList = _widgetIdOrWidget.getCallbackList();
                _widgetIdOrWidget = _widgetIdOrWidget.getId();
			if(typeof _widgetIdOrWidget == "string" && Class.isA(CallbackList, _callbackList)){
				var widget = this.discoverer.getComponent(_widgetIdOrWidget);
				if (widget) {
Stefanie Lemcke's avatar
Stefanie Lemcke committed
					this.subscribeTo(widget, _callbackList);			
					this.callbacks.putAll(_callbackList);			
					var callsList = _callbackList.getItems();		
					for(var x in callsList){
						var singleCallback = callsList[x];			
						var typeList = singleCallback.getAttributeTypes().getItems();
						for(var y in typeList){
							var singleType = typeList[y];
							this.addOutAttribute(singleType);
                    this.addWidget(_widgetIdOrWidget);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Removes subscribed Widgets and deletes the entry 
		 * for subscribers in the associated Widget.
		 * 
		 * @public
	   	 * @alias unsubscribeFrom
		 * @memberof Aggregator#
		 * @param {String} _widgetId Widget that should be removed.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'public unsubscribeFrom' : function(_widgetId){
			if(typeof _widgetId == "string") {
				var widget = this.discoverer.getComponent(_widgetId);
				if (widget) {
Stefanie Lemcke's avatar
Stefanie Lemcke committed
					console.log('aggregator unsubscribeFrom: ' + widget.getName());
					widget.removeSubscriber(this.id);
					this.removeWidget(_widgetId);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Puts context data to Widget and expects an array.
		 * 
		 * @override
		 * @public
	   	 * @alias putData
		 * @memberof Aggregator#
		 * @param {(AttributeList|Array)}  _data data that shall be input
Stefanie Lemcke's avatar
Stefanie Lemcke committed
	     */
		'override public putData' : function(_data){
Stefanie Lemcke's avatar
Stefanie Lemcke committed
			if(_data instanceof Array){
				list = _data;
			} else if (Class.isA(AttributeList, _data)) {
Stefanie Lemcke's avatar
Stefanie Lemcke committed
				list = _data.getItems();
			}
			for(var i in list){
				var x = list[i];
				if(Class.isA(Attribute, x ) && this.isOutAttribute(x)){
					this.addOutAttribute(x);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
					if(this.db){
						this.store(x);
					}
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		
		/**
		 * Calls the given Interpreter for interpretation the data.
		 * 
		 * @public
	   	 * @alias interpretData
		 * @memberof Aggregator#
		 * @param {String} _interpreterId ID of the searched Interpreter
		 * @param {?function} _function for additional actions, if an asynchronous function is used
	     */
		'public interpretData' : function(_interpreterId, _inAttributeValues, _outAttributeValues, _function){
Stefanie Lemcke's avatar
Stefanie Lemcke committed
			var interpreter = this.discoverer.getComponent(_interpreterId);
			if (Class.isA(Interpreter, interpreter)) {
				interpreter.callInterpreter(_inAttributeValues, _outAttributeValues, _function);
Stefanie Lemcke's avatar
Stefanie Lemcke committed
			}
		},
		
		/**
		 * Initializes the database with the specified name.
		 * 
		 * @protected
	   	 * @alias initStorage
		 * @memberof Aggregator#
		 * @param {String} _name Name of the Storage
	     */
		'protected initStorage' : function(_name){
			this.db = new Storage(_name, 7200000, 5);
		},
		
		/**
		 * Stores the data.
		 * 
		 * @protected
	   	 * @alias store
		 * @memberof Aggregator#
		 * @param {AttributeValue} _attributeValue data that should be stored
	     */
		'protected store' : function(_attributeValue){
			this.db.store(_attributeValue);
		},
		
		/**
		 * Queries the database and returns the last retrieval result. 
		 * It may be that the retrieval result is not up to date, 
		 * because an asynchronous function is used for the retrieval.
		 * For retrieving the current data, this function can be used as callback function
		 * in retrieveStorage().
		 * 
		 * @public
	   	 * @alias queryAttribute
		 * @memberof Aggregator#
		 * @param {String} _name Name of the searched AtTributes.
		 * @param {?function} _function for alternative  actions, because an asynchronous function is used
	     */
		'public queryAttribute' : function(_name, _function){
			this.db.retrieveAttributes(_name, _function);	
		},
		
		/**
		 * Queries a specific table and only actualizes the storage cache.
		 * For an alternativ action can be used a callback.
		 * 
		 * @public
	   	 * @alias retrieveStorage
		 * @memberof Aggregator#
		 * @returns {RetrievalResult}
	     */
		'public retrieveStorage' : function(){
			return this.db.getCurrentData();
		},
		
		/**
		 * Returns an overview about the stored attributes.
		 * It may be that the overview about the stored attributes is not up to date, 
		 * because an asynchronous function is used for the retrieval.
		 * For retrieving the current data, this function can be used as callback function
		 * in queryTables().
		 * 
		 * @public
	   	 * @alias getStorageOverview
		 * @memberof Aggregator#
		 * @returns {?Array}
	     */
		'public getStorageOverview' : function(){
			return this.db.getAttributesOverview();
		},
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		/**
		 * Only updates the attribute cache in the database.
		 * For an alternative action a callback can be used.
Stefanie Lemcke's avatar
Stefanie Lemcke committed
		 * @public
	   	 * @alias queryTables
		 * @memberof Aggregator#
		 * @param {?function} _function for alternative actions, because an asynchronous function is used
	     */
		'public queryTables' : function(_function){
			this.db.getAttributeNames(_function);
        },

         * Updates the information for the widget with the provided ID and calls the callback afterwards.
         *
         * @public
         * @virtual
         * @alias queryReferencedWidget
         * @memberof Aggregator#
         * @param {String} _widgetId The ID of the widget to query.
         * @param {Callback} _callback The callback to query after the widget was updated.
         */
        'virtual public queryReferencedWidget' :function(_widgetId, _callback){
            this.discoverer.getWidget(_widgetId).updateWidgetInformation(_callback);
        },

		/**
		 * Returns the UUIDs of all connected widgets and interpreters.
		 *
		 * @private
		 * @alias getComponentUUIDs
		 * @memberof Aggregator#
		 * @returns {Array.<T>} The UUIDs.
		 */
        'private getComponentUUIDs': function() {
            var uuids = [];
			uuids = uuids.concat(this.widgets);
			for (var index in this.interpretations) {
				var theInterpretation = this.interpretations[index];
				uuids.push(theInterpretation.interpreterId);

			}
			return uuids;
        },

		/**
		 * Return true if a component with the provided UUID was connected to the aggregator.
		 *
		 * @private
		 * @alias hasComponent
		 * @memberof Aggregator#
		 * @param {String} uuid The UUID of the component to check.
		 * @returns {boolean}
		 */
        'private hasComponent': function(uuid) {
            return jQuery.inArray(uuid, this.getComponentUUIDs()) != -1;
        },

		/**
		 *
		 * @alias doesSatisfyAttributeType
		 * @returns {boolean}
		 */
        'override public doesSatisfyAttributeType': function(_attribute) {
            var componentUUIDs = this.getComponentUUIDs();
            var doesSatisfy = false;

            for (var index in componentUUIDs) {
                var theComponent = this.discoverer.getComponent(componentUUIDs[index]);
                if (theComponent.doesSatisfyAttributeType(_attribute)) {
                    doesSatisfy = true;
                }
            }

            return doesSatisfy;
        },

		/**
		 * Searches for components that can satisfy the requested attributes. Through recursion it is possible to search
		 * for components that satisfy attributes of components that have been found in the process.
		 *
		 * @private
		 * @alias getComponentsForUnsatisfiedAttributeTypes
		 * @memberof Aggregator#
		 * @param {AttributeList} _unsatisfiedAttributes A list of attributes that components should be searched for.
		 * @param {boolean} _all If true all attributes must be satisfied by a single component.
		 * @param {Array} _componentTypes An array of components classes that should be searched for (e.g. Widget, Interpreter and Aggregator).
		 */
        'private getComponentsForUnsatisfiedAttributeTypes': function(_unsatisfiedAttributes, _all, _componentTypes) {
			// ask the discoverer for components that satisfy the requested components
            var relevantComponents = this.discoverer.getComponentsByAttributes(_unsatisfiedAttributes, _all, _componentTypes);
            console.log("I found "+relevantComponents.length+" component(s) of type "+_componentTypes+" that might satisfy the requested attributes.");

			// iterate over all found components
            for(var index in relevantComponents) {
				// get the component
                var theComponent = relevantComponents[index];
                console.log("Let's look at component "+theComponent.getName()+".");

				// if the component was added before, ignore it
                if (!this.hasComponent(theComponent.getId())) {
                    var outAttributes = theComponent.getOutAttributes().getItems();

                    // if component is a widget and it wasn't added before, subscribe to its callbacks
                    if (Class.isA(Widget, theComponent)) {
                        console.log("It's a widget.");

                        this.addWidgetSubscription(theComponent);
                        // remove satisfied attributes
                        for (var widgetOutAttributeIndex in outAttributes) {
                            var widgetOutAttribute = outAttributes[widgetOutAttributeIndex];
							// add the attribute type to the aggregators list of handled attribute types
                            if (!this.getOutAttributes().containsTypeOf(widgetOutAttribute)) this.addOutAttribute(widgetOutAttribute);
                            console.log("I can now satisfy attribute "+widgetOutAttribute+" with the help of "+theComponent.getName()+"! That was easy :)");
                            _unsatisfiedAttributes.removeAttributeWithTypeOf(widgetOutAttribute);
                        }
                    } else if (Class.isA(Interpreter, theComponent)) { // if the component is an interpreter and all its in attributes can be satisfied, add the interpreter
                        console.log("It's an interpreter.");

                        var inAttributes = theComponent.getInAttributes().getItems();
                        var canSatisfyInAttributes = true;

						// iterate over the attributes needed to satisfy the interpreter
                        for (var inAttributeIdentifier in inAttributes) {
							// get the attribute
                            var theInAttribute = inAttributes[inAttributeIdentifier];
                            console.log("The interpreter needs the attribute "+theInAttribute+".");

							// if required attribute is not already satisfied by the aggregator search for components that do
                            if (!this.doesSatisfyAttributeType(theInAttribute)) {
                                console.log("It seems that I can't satisfy "+theInAttribute+", but I will search for components that can.");
                                var newAttributeList = new AttributeList();
                                newAttributeList.put(theInAttribute);
                                this.getComponentsForUnsatisfiedAttributeTypes(newAttributeList, false, [Widget, Interpreter]);
								// if the attribute still can't be satisfied drop the interpreter
                                if (!this.doesSatisfyAttributeType(theInAttribute)) {
                                    console.log("I couldn't find a component to satisfy "+theInAttribute+". Dropping interpreter "+theComponent.getName()+". Bye bye.");
                                    canSatisfyInAttributes = false;
                                    break;
                                }
                            } else {
                                console.log("It seems that I already satisfy the attribute "+theInAttribute+". Let's move on.");
                            }
                        }

                        if (canSatisfyInAttributes) {
                            // remove satisfied attribute
                            for (var interpreterOutAttributeIndex in outAttributes) {
                                var interpreterOutAttribute = outAttributes[interpreterOutAttributeIndex];
								// add the attribute type to the aggregators list of handled attribute types
								for (var unsatisfiedAttributeIndex in _unsatisfiedAttributes.getItems()) {
									var theUnsatisfiedAttribute = _unsatisfiedAttributes.getItems()[unsatisfiedAttributeIndex];
									if (theUnsatisfiedAttribute.equalsTypeOf(interpreterOutAttribute)) {
										this.addOutAttribute(theUnsatisfiedAttribute);
										console.log("I can now satisfy attribute "+theUnsatisfiedAttribute+" with the help of "+theComponent.getName()+"! Great!");
										this.interpretations.push(new Interpretation(theComponent.getId(), theComponent.getInAttributes(), new AttributeList().withItems([theUnsatisfiedAttribute])));
								_unsatisfiedAttributes.removeAttributeWithTypeOf(interpreterOutAttribute, true);
						} else {
                            console.log("Found interpreter but can't satisfy required attributes.");
                            for (var j in theComponent.getInAttributes().getItems()) {
                                console.log("Missing "+theComponent.getInAttributes().getItems()[j]+".");
                            }
                        }
                    }
                } else {
                    console.log("Aggregator already has component "+theComponent.getName()+". Nothing to do here ;)");
                }
            }
        },

		/**
		 * After the aggregator finished its setup start searching for component that satisfy the attributes that where requrested.
		 *
		 * @public
		 * @virtual
		 * @alias didFinishSetup
		 * @memberof Aggregator#
		 */
        'virtual public didFinishSetup': function() {
            unsatisfiedAttributes = this.getOutAttributes().clone();

            // get all widgets that satisfy attribute types
            this.getComponentsForUnsatisfiedAttributeTypes(unsatisfiedAttributes, false, [Widget]);
            // get all interpreters that satisfy attribute types
            this.getComponentsForUnsatisfiedAttributeTypes(unsatisfiedAttributes, false, [Interpreter]);

			console.log("Unsatisfied attributes: "+unsatisfiedAttributes.size());
			console.log("Satisfied attributes: "+this.getOutAttributes().size());
			console.log("Interpretations "+this.interpretations.length);
         * Updates all the widgets referenced by the aggregator and calls the provided callback afterwards.
		 * @public
		 * @virtual
		 * @alias queryReferencedWidgets
		 * @memberof Aggregator#
         * @param {Function} _callback The callback to query after all the widget where updated.
         */
        'virtual public queryReferencedWidgets': function(_callback) {
            var self = this;
            var completedQueriesCounter = 0;

            if (this.widgets.length > 0) {
                for (var index in this.widgets) {
                    var theWidgetId = this.widgets[index];
                    this.queryReferencedWidget(theWidgetId, function () {
                        completedQueriesCounter++;
                        if (completedQueriesCounter == self.widgets.length) {
                            if (_callback && typeof(_callback) == 'function') {
                                _callback(self.getOutAttributes());
                    });
                }
            } else {
				if (_callback && typeof(_callback) == 'function') {
                    _callback(self.getOutAttributes());
Tobias Moebert's avatar
Tobias Moebert committed
        },

		/**
		 * Let's all connected interpreters interpret data.
		 *
		 * @public
		 * @alias queryReferencedInterpreters
		 * @memberof Aggregator#
		 * @param {Function} _callback The callback to query after all the interpreters did interpret data.
		 */
        'public queryReferencedInterpreters': function(_callback) {
            var self = this;
            var completedQueriesCounter = 0;

			if (this.interpretations.length > 0) {
				for (var index in this.interpretations) {
					var theInterpretation = this.interpretations[index];
					var theInterpreterId = theInterpretation.interpreterId;
					var interpretationInAttributeValues = this.getOutAttributes(theInterpretation.inAttributeTypes);
					var interpretationOutAttributeValues = this.getOutAttributes(theInterpretation.outAttributeTypes);

					self.interpretData(theInterpreterId, interpretationInAttributeValues, interpretationOutAttributeValues, function(_interpretedData) {
						for (var j in _interpretedData.getItems()) {
							var theInterpretedData = _interpretedData.getItems()[j];

							self.addOutAttribute(theInterpretedData);
								self.store(theInterpretedData);
							}
						}
						completedQueriesCounter++;
						if (completedQueriesCounter == self.interpretations.length) {
							if (_callback && typeof(_callback) == 'function') {
								_callback(self.getOutAttributes());
							}
						}
					});
				}
			} else {
				if (_callback && typeof(_callback) == 'function') {
					_callback(self.getOutAttributes());
Tobias Moebert's avatar
Tobias Moebert committed
        },

		/**
		 * Query all referenced widgets and afterwards all connected interpreters.
		 *
		 * @public
		 * @alias queryReferencedComponents
		 * @memberof Aggregator#
		 * @param {Function} _callback the callback to query after all components did finish their work.
		 */
        'public queryReferencedComponents': function(_callback) {
            var self = this;

            this.queryReferencedWidgets(function(_attributeValues) {
                self.queryReferencedInterpreters(function(_attributeValues) {
                    if (_callback && typeof(_callback) == 'function') {
                        _callback(_attributeValues);
                    }
                });
            });
Stefanie Lemcke's avatar
Stefanie Lemcke committed

	return Aggregator;
});