1 var Class = require("./Class");
  2 var Private = Class.Private;
  3 var Protected = Class.Protected;
  4 var Public = Class.Public;
  5 var Static = Class.Static;
  6 var Final = Class.Final;
  7 var Property = Class.Property;
  8 
  9 var EventHandler = new Class("EventHandler", {
 10     //Private members
 11 	listeners: Private(null),
 12 	
 13     //Private methods
 14     addListener: Private(function addListener(evnt, fn, once, related){
 15         if (this.listeners == null)
 16             this.listeners = {};
 17 
 18 		if (fn instanceof Function) {
 19 			if (!this.listeners.hasOwnProperty(evnt))
 20 				this.listeners[evnt] = [];
 21 				
 22 			this.listeners[evnt].push({ once: once, handler: fn, related: related });
 23 		}
 24 		else
 25 			throw TypeError("Only functions can be event handlers!");		
 26     }),
 27 	removeRelatives: Private(function removeRelatives(relatives) {
 28 		if (Array.isArray(relatives) || (relatives instanceof Array)) {
 29 			for (var i=0; i<relatives.length; ++i) {
 30                 var relative = relatives[i];
 31                 this.removeEventListener(relative.event, relative.method);
 32             }
 33 		}
 34 	}),
 35     
 36     //Protected Methods
 37     deferCall: Protected(function deferCall(fn, params) {
 38         setTimeout(this.Delegate(function runDeferredCall() {
 39             fn.apply(undefined, params);
 40         }), 0);
 41     }),
 42 
 43     //Public Methods
 44 	addEventListener: Public(function addEventListener(evnt, fn, related) {
 45         this.addListener(evnt, fn, false, related);
 46 	}),
 47 	addEventListenerOnce: Public(function addEventListenerOnce(evnt, fn, related) {
 48         this.addListener(evnt, fn, true, related);
 49 	}),
 50 	removeEventListener: Public(function removeEventListener(evnt, fn, withRelatives) {
 51         if (this.listeners == null)
 52             this.listeners = {};
 53 
 54 		if (this.listeners.hasOwnProperty(evnt)) {
 55             var handlers = this.listeners[evnt];
 56 			var index = -1;
 57             
 58             while ((++index < handlers.length) && (handlers[index].handler !== fn));
 59 			
 60 			if (index  < handlers.length) {
 61 				var handler = handlers[index];
 62 				this.listeners[evnt].splice(index, 1);
 63 			}
 64 
 65 			if (withRelatives)
 66 				this.removeRelatives(handler.related);
 67 		}
 68 	}),
 69     addRelatedEventListeners: Public(function addRelatedEventListeners(evntList) {
 70         for (var i=0; i<evntList.length; ++i) {
 71             var evntHandler = evntList[i];
 72             var relatives = evntList.slice(0);
 73             relatives.splice(i, 1);
 74             this.addEventListener(evntHandler.event, evntHandler.method, relatives);
 75         }
 76     }),
 77     addRelatedEventListenersOnce: Public(function addRelatedEventListenersOnce(evntList) {
 78         for (var i=0; i<evntList.length; ++i) {
 79             var evntHandler = evntList[i];
 80             var relatives = evntList.slice(0);
 81             relatives.splice(i, 1);
 82             this.addEventListenerOnce(evntHandler.event, evntHandler.method, relatives);
 83         }
 84     }),
 85     removeAllHandlers: Public(function removeAllHandlers(evnt) {
 86         if (evnt && this.listeners.hasOwnProperty(evnt))
 87             this.listeners[evnt] = [];
 88         else if (!evnt)
 89             this.listeners = {};
 90     }),
 91 	fireEvent: Public(function fireEvent(evnt, params) {
 92         if (this.listeners == null)
 93             this.listeners = {};
 94 
 95 		if (this.listeners.hasOwnProperty(evnt)) {
 96 			var handlers = this.listeners[evnt];
 97             var keep = [];
 98 			
 99             console.log("Processing event: " + evnt);
100 			for (var i=0; i<handlers.length; ++i) {
101                 var handler = handlers[i];
102                 //Queue the event to be handled at the next earliest convenience...
103 				this.deferCall(handler.handler, [ params ]);
104                 
105                 if (!handler.once)
106                     keep.push(handler);
107                 else if (handler.related)
108                     this.removeRelatives(handler.related);
109             }
110             
111             this.listeners[evnt] = keep;
112 		}
113 	}),
114 	fireEventSync: Public(function fireEvent(evnt, params) {
115         if (this.listeners == null)
116             this.listeners = {};
117 
118 		if (this.listeners.hasOwnProperty(evnt)) {
119 			var handlers = this.listeners[evnt];
120             var keep = [];
121 
122             console.log("Processing event: " + evnt);
123 			for (var i=0; i<handlers.length; ++i) {
124                 var handler = handlers[i];
125                 //Handle this event now...
126 				handler.handler(params);
127 
128                 if (!handler.once)
129                     keep.push(handler);
130                 else if (handler.related)
131                     this.removeRelatives(handler.related);
132             }
133 
134             this.listeners[evnt] = keep;
135 		}
136 	})
137 
138 });
139 
140 module.exports = EventHandler;
141