if (!this.Rf) this.Rf = {};
(function(ns, $) {

/**
 * Base event class
 * @param {String} type The type of the event
 * @param {String} target The dispatcher of the event
 * @param {Object} (Optional) Data associated with this event
 */
ns.Event = function(type, target, data) {
	this.Type = type;
	this.Target = target;
	this.Data = data;
	this.TimeStamp = new Date();
	this._Canceled = false;
};
ns.Event.prototype = {
	constructor : ns.Event,
	/**
	 * Prevents the event from being passed any further
	 */
	Stop : function() {
		this._Canceled = true;
	},
	/**
	 * Converts the event to a string
	 */
	toString : function() {
		var result = '[Event[';
		for (var k in this) {
			if (this[k] instanceof Function) continue;
			result += k + '=' + this[k] + ';';
		}
		return result + ']]';
	}
};

/**
 * Base class for objects that can use events
 */
ns.EventDispatcher = function(options) {
	this._Events = {};
	if (options) for (var prop in options) this[prop] = options[prop];
};
ns.EventDispatcher.prototype = {
	constructor : ns.EventDispatcher,
	/**
	 * Associates a callback with one of this object's events
	 * @param {String} type The type name of the event to listen for
	 * @param {Function} callback A function to be executed when the event occurs.
	 */
	Bind : function(type, callback) {
		var callbacks = this._Events[type];
		if (!callbacks) callbacks = this._Events[type] = [];
		callbacks.push(function(e) {
			try {
				callback.call(this, e);
			}
			catch (err) {
				setTimeout(function() { throw err.message }, 0);
			}
		});
		return this;
	},
	/**
	 * Removes all callbacks or a specific callback from this object's event listeners
	 * @param {String} type The type of event
	 * @param {Function} callback (Optional) A specific callback to remove. If this argument is not supplied, all callbacks for that event type are removed.
	 */
	Unbind : function(type, callback) {
		var callbacks = this._Events[type];
		if (callbacks && callbacks.length > 0) {
			if (callback) {
				for (var i = callbacks.length - 1; i >= 0; i--) {
					if (callbacks[i] == callback) callbacks.splice(i, 1);
				}
			}
			else {
				callbacks.splice(0, callbacks.length);
			}
		}
		return this;
	},
	/**
	 * Generates an event
	 * @param {Object} event Either an Rf.Event object or an event type name
	 */
	Dispatch : function(event) {
		if (typeof event == 'string') event = new ns.Event(event, this);
		var callbacks = this._Events[event.Type],
			i, j;
		if (callbacks && (j = callbacks.length) > 0) {
			for (i = 0; i < j; i++) {
				callbacks[i].call(this, event);
				if (event._Canceled) break;
			}
		}
		return this;
	}
};

})(Rf, jQuery);

