1 var Event = require('./Event.js').Event;
  2 var Class = require("../../mootools/mootools-node.js").Class;
  3 
  4 /**
  5  * EventDispatcher
  6  * @class EventDispatcher provides listening and dispatching events functionality
  7  * @requires Class
  8  * @requires Event
  9  */
 10 var EventDispatcher = function() {
 11 
 12     /**
 13      * @property {Object} _eventsArray
 14      * @private
 15      */
 16     this._eventsArray = new Object();
 17 
 18     /**
 19      * Checks if given event type listener is registered
 20      * @param {String} type Event type
 21      * @returns {Boolean} True if listener of given type is registered 
 22      */
 23     this.hasEventListener = function(type) {
 24         if (this._eventsArray.hasOwnProperty(type) && this._eventsArray[type].length > 0){
 25             return true;
 26         }
 27         return false;
 28     };
 29 
 30     /**
 31      * Adding listener
 32      * @param {String} type Event type
 33      * @param {Function} callbackFunction Function that will be called if event of givent type will ocurr. 
 34      */
 35     this.addEventListener = function(type, callbackFunction, context){
 36         //creating new listener object
 37         var listener = new Object();
 38         listener.callbackFunction = callbackFunction;
 39         listener.context = (context) ? context : this;
 40         //creating space for listeners of given type
 41         if (!this.hasEventListener(type)){
 42             this._eventsArray[type] = new Array();
 43         }
 44         
 45         var hasBeenAddedBefore = false;
 46         
 47         for(var i = 0, l = this._eventsArray[type].length; i < l; i++){
 48             if(this._eventsArray[type][i].callbackFunction == callbackFunction && this._eventsArray[type][i].context == context){
 49                 hasBeenAddedBefore = true;
 50                 break;
 51             }
 52         }
 53         
 54         if(hasBeenAddedBefore){
 55             return false;
 56         }
 57         
 58         //adding listener
 59         this._eventsArray[type].push(listener);
 60 
 61         return this;
 62     };
 63 
 64     /**
 65      * Dispatches event
 66      * @param {Event} e Event object to be dispatched
 67      */
 68     this.dispatchEvent = function(e) {
 69         if (this.hasEventListener(e.type)) {
 70             //creating private function to pass listener by value otherwise nextTick oparates on last loop iteration variables states 
 71             var that = this;
 72             var callLater = function(listener) {                
 73                 //passing script execution to end of script execution queue
 74                 //different in client "window.setTimeout"
 75                 //process.nextTick( function(){
 76                 //setTimeout( function(){ 
 77                     listener.callbackFunction.call(listener.context, e);
 78                 //}, 0);
 79             };
 80             for (var i = 0; i < this._eventsArray[e.type].length; i++) {
 81                 e.target = this;
 82                 var listener = this._eventsArray[e.type][i];
 83                 if ( listener.callbackFunction != undefined ){
 84                     callLater(listener);
 85                 }
 86                 else{
 87                     throw "Callback function for Event type: [ " + e.type + " ] is undefined. Please check your addEventListener statement.";
 88                 }
 89             }
 90         }
 91     };
 92 
 93     /**
 94      * Remove listener
 95      * @param {String} type Event type
 96      * @param {Function} callbackFunction Function that was given on adding event listener. 
 97      */
 98     this.removeEventListener = function(type, callbackFunction) {
 99         var i = 0;
100         if (!this.hasEventListener(type)){
101             throw 'Listeners of given type: "' + type + '" do not exists.';
102         }             
103         while(i < this._eventsArray[type].length && this._eventsArray[type][i].callbackFunction != callbackFunction) {
104             i++;
105         }
106         if(i < this._eventsArray[type].length){
107             if(this._eventsArray[type].length > 1){
108                 this._eventsArray[type].splice(i, 1);
109             }
110             else{
111                 delete this._eventsArray[type];
112             }
113             return true;
114         }
115         return false;
116     };
117 
118     /**
119      * Remove group of listeners or all listeners
120      * @param {String} type Event type if given removes all listeners of given type, otherwise removes all listeners. 
121      */
122     this.removeAllEventListeners = function(type) { 
123         if(type != undefined){
124             if(this.hasEventListener(type)){
125                 delete this._eventsArray[type];
126                 return true;
127             }
128             else{
129                 throw 'Listeners of given type: "' + type + '" do not exists.';
130             }
131             return false;
132         }
133         else{
134             delete this._eventsArray;
135             this._eventsArray = new Object();
136             return true;
137         }
138     };
139 };
140 
141 EventDispatcher = new Class(new EventDispatcher());
142 exports.EventDispatcher = EventDispatcher;
143