1 var func = require("./functions"),
  2 		obj = require("./object"),
  3 		define = require("../define").define;
  4 
  5 var comb = exports;
  6 
  7 
  8 var wrapper = function() {
  9 	return function() {
 10 		var c = arguments.callee, listeners = c.__listeners, func = c.func, r;
 11 		if (func) {
 12 			r = func.apply(this, arguments);
 13 		}
 14 		for (var i = 0; i < listeners.length; i++) {
 15 			var lis = listeners[i];
 16 			if (lis) {
 17 				lis.apply(this, arguments);
 18 			}
 19 		}
 20 		return r;
 21 
 22 	}
 23 };
 24 
 25 
 26 var listeners = {};
 27 obj.merge(comb, {
 28             /**@lends comb*/
 29 			/**
 30 			 * Disconnects a listener to a function
 31 			 * @param {handle} A handle returned from comb.connect
 32 			 */
 33 			disconnect : function(handle) {
 34 				if (handle && handle.length == 3) {
 35 					var obj = handle[0], method = handle[1], cb = handle[2];
 36 					if (typeof method != "string") throw "comb.disconnect : When calling disconnect the method must be string";
 37 					var scope = obj || global, ls;
 38 					if (typeof scope[method] == "function") {
 39 						ls = scope[method].__listeners;
 40 						if (ls && cb-- > 0) {
 41 							//we dont want to splice it because our indexing will get off
 42 							ls[cb] = null;
 43 						}
 44 					} else {
 45 						throw new Error("unknown method " + method + " in object " + obj);
 46 					}
 47 				} else {
 48 					throw "comb.disconnect : invalid handle"
 49 				}
 50 			},
 51 
 52 			/**
 53 			 * Function to listen when other functions are called
 54 			 *
 55 			 * @example
 56 			 *
 57 			 *  comb.connect(obj, "event", myfunc);
 58 			 *  comb.connect(obj, "event", "log", console);
 59 			 *
 60 			 * @param {Object} obj the object in which the method you are connection to resides
 61 			 * @param {String} method the name of the method to connect to
 62 			 * @param {Function} cb the function to callback
 63 			 * @param {Object} [scope] the scope to call the specified cb in
 64 			 *
 65 			 * @returns {Array} handle to pass to {@link comb.disconnect}
 66 			 */
 67 			connect : function(obj, method, cb, scope) {
 68 				var index;
 69 				if (typeof method != "string") throw new Error("When calling connect the method must be string");
 70 				if (!func.isFunction(cb)) throw new Error("When calling connect callback must be a string");
 71 				var scope = obj || global, listeners, newMethod;
 72 				if (typeof scope[method] == "function") {
 73 					listeners = scope[method].__listeners;
 74 					if (!listeners) {
 75 						newMethod = wrapper();
 76 						newMethod.func = obj[method];
 77 						listeners = (newMethod.__listeners = []);
 78 						scope[method] = newMethod;
 79 					}
 80 					index = listeners.push(cb);
 81 				} else {
 82 					throw new Error("unknow method " + method + " in object " + obj);
 83 				}
 84 				return [obj, method, index];
 85 			},
 86 
 87 
 88 			/**
 89 			 * Broadcasts an event to all listeners
 90 			 * NOTE : the function takes a variable number of arguments
 91 			 *        i.e. all arguments after the topic will be passed to the listeners
 92 			 *
 93 			 * @example
 94 			 *
 95 			 *
 96 			 * comb.broadcast("hello", "hello world");
 97 			 * //the args "hello" and "world" will be passed to any listener of the topic
 98 			 * //"hello"
 99 			 * comb.broadcast("hello", "hello", "world");
100 			 *
101 			 * @param  {String} topic the topic to brodcast
102 			 * @param params the information to bradcast
103 			 */
104 			broadcast : function() {
105 				var args = Array.prototype.slice.call(arguments);
106 				var topic = args.splice(0, 1)[0];
107 				if (topic) {
108 					var list = listeners[topic];
109 					if (list) {
110 						for (var i = list.length - 1; i >= 0; i--) {
111 							var han = list[i], cb = han.cb;
112 							if (cb) {
113 								cb.apply(this, args);
114 							}
115 						}
116 					}
117 				}
118 			},
119 
120 			/**
121 			 * Listen for the broadcast of certain events
122 			 *
123 			 * @example
124 			 *  comb.listen("hello", function(arg1, arg2){
125 			 *     console.log(arg1);
126 			 *     console.log(arg2);
127 			 *  });
128 			 *
129 			 * @param {String} topic the topic to listen for
130 			 * @param {Function} callback the funciton to call when the topic is published
131 			 *
132 			 * @returns a handle to pass to {@link comb.unListen}
133 			 */
134 			listen : function(topic, callback) {
135 				if (!func.isFunction(callback)) throw new Error("callback must be a function");
136 				var handle = {
137 					topic : topic,
138 					cb : callback,
139 					pos : null
140 				};
141 				var list = listeners[topic];
142 				if (!list) {
143 					list = (listeners[topic] = []);
144 				}
145 				list.push(handle);
146 				handle.pos = list.length - 1;
147 				return handle;
148 			},
149 
150 			/**
151 			 * Disconnects a listener
152 			 *
153 			 * @param handle a handle returned from {@link comb.listen}
154 			 */
155 			unListen : function(handle) {
156 				if (handle) {
157 					var topic = handle.topic, list = listeners[topic];
158 					if (list) {
159 						for (var i = list.length - 1; i >= 0; i--) {
160 							if (list[i] == handle) {
161 								list.splice(i, 1);
162 							}
163 						}
164 						if (!list.length) {
165 							delete listeners[topic];
166 						}
167 					}
168 				}
169 			}
170 
171 		});
172 
173