1 var func = require("../base/functions"),
  2 		define = require("../define").define;
  3 
  4 
  5 var Broadcaster = define(null, {
  6 			instance : {
  7 				/** @lends comb.plugins.Broadcaster.prototype */
  8 				/**
  9 				 * Plugin to allow a class to easily broadcast events
 10 				 *
 11 				 * @example
 12 				 *
 13 				 * var Mammal = define(comb.plugins.Broadcaster, {
 14 				 *   instance : {
 15 				 *
 16 				 *      constructor: function(options) {
 17 				 *          options = options || {};
 18 				 *          this._super(arguments);
 19 				 *          this._type = options.type || "mammal";
 20 				 *      },
 21 				 *
 22 				 *      speak : function() {
 23 				 *          var str = "A mammal of type " + this._type + " sounds like";
 24 				 *          this.broadcast("speak", str);
 25 				 *          this.onSpeak(str);
 26 				 *          return str;
 27 				 *      },
 28 				 *
 29 				 *      onSpeak : function(){}
 30 				 *    }
 31 				 * });
 32 				 *
 33 				 *
 34 				 * var m = new Mammal({color : "gold"});
 35 				 * m.listen("speak", function(str){
 36 				 *      //called back from the broadcast event
 37 				 *       console.log(str);
 38 				 * });
 39 				 * m.speak();
 40 				 *
 41 				 * @constructs
 42 				 */
 43 				constructor : function() {
 44 					this.__listeners = {};
 45 				},
 46 
 47 				/**
 48 				 * Broadcasts an event from an object
 49 				 *
 50 				 * @param name the name of the event to broadcast
 51 				 * @param {Object|String|Function|Date|Number} [args]  variable number of arguments to pass to listeners, can be anything
 52 				 */
 53 				broadcast : function(topic, args) {
 54 					var args = Array.prototype.slice.call(arguments, 0), topic = args.shift();
 55 					if (topic && topic in this.__listeners) {
 56 						var list = this.__listeners[topic], i = list.length - 1;
 57 						while (i >= 0) {
 58 							list[i--].cb.apply(this, args);
 59 						}
 60 					}
 61 				},
 62 
 63 				/**
 64 				 * Listens to a broadcasted event
 65 				 * Simimlar to {@link comb.listen}
 66 				 *
 67 				 * @param {String} topic the topic to listen to
 68 				 * @param {Function} callback the function to callback on event publish
 69 				 *
 70 				 * @returns {Array} handle to disconnect a topic
 71 				 */
 72 				listen : function(topic, callback) {
 73 					if (!func.isFunction(callback)) throw new Error("callback must be a function");
 74 					var handle = {
 75 						topic : topic,
 76 						cb : callback
 77 					};
 78 					var list = this.__listeners[topic];
 79 					if (!list) {
 80 						list = (this.__listeners[topic] = [handle]);
 81 						handle.pos = 0;
 82 					} else {
 83 						handle.pos = list.push(handle);
 84 					}
 85 					return handle;
 86 				},
 87 
 88 				/**
 89 				 * Disconnects a listener
 90 				 * Similar to {@link comb.unListen}
 91 				 *
 92 				 * @param  handle disconnect a handle returned from Broadcaster.listen
 93 				 */
 94 				unListen : function(handle) {
 95 					if (handle) {
 96 						var topic = handle.topic;
 97 						if (topic in this.__listeners) {
 98 							var listeners = this.__listeners, list = listeners[topic];
 99 							if (list) {
100 								for (var i = list.length - 1; i >= 0; i--) {
101 									if (list[i] == handle) {
102 										list.splice(i, 1);
103 										break;
104 									}
105 								}
106 							}
107 						}
108 					}
109 				}
110 			}
111 		});
112 
113 exports = module.exports = Broadcaster;