      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