/*
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% EventControl %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
	/**
	 *	EventControl
	 *	The event control class provides a way to chain callbacks on element event handlers.
	 *
	 *	@constructor
	 */
	function EventControl() {
		// This is mainly static, no need to instantiate
	}
	
	/**
	 *	Cancel an event
	 *
	 *	@param e The event to cancel
	 *
	 *	@return false
	 */
	EventControl.cancel = function(e) {
		var ev = (document.all ? event : e);
		ev.cancelBubble = true;
		return false;
	}
	
	/**
	 *	Add a callback to a given handler
	 *
	 *	@param {Object} obj The object which you want to monitor for events
	 *	@param {String} method The name of the handler you want to monitor 
	 *	@param {Function} callback The method to execute when this handler fires
	 *
	 *	@return an event monitoring object
	 */
	EventControl.listen = function(obj, method, callback, scope) {
		if (obj == undefined) {
			console.log('bad handler: ', obj, method, callback, scope);
		}
		if (obj.i_listeners == undefined) {
			obj.i_listeners = Array();
		}
		if (obj.i_listeners[method] == undefined) {
			obj.i_listeners[method] = Array();
		}
		var em1 = new EventMonitor(obj, method, callback, undefined, scope);
		obj.i_listeners[method][obj.i_listeners[method].length] = em1;
		if (obj[method] != undefined && obj[method] != EventControl.handleTrigger) {
			var em2 = new EventMonitor(obj, method, obj[method], true);
			obj.i_listeners[method][obj.i_listeners[method].length] = em2;
		}
		obj[method] = EventControl.handleTrigger;
		return em1;
	}
	
	
	/**
	 *	The common handler for all event triggers
	 *
	 *	@param e The event which was just triggered (on some browsers)
	 *
	 *	@return false if any callback returned false; true if there were no false returns,
	 *		and there was at least one true return; undefined otherwise.
	 */
	EventControl.handleTrigger = function(e) {
		var ev = (e == undefined && Environment.isIE() ? event : e);
		if (e != undefined) {
			ev = e;
		}
		
		if (ev == undefined) {
			return true;
		}
		
		if (ev.type == undefined) {
			console.log('unknown event, missing type');
			return true;
		}

		ev.originalScope = this;
		var ret = true;
		var list = this.i_listeners["on" + ev.type];
		if (list != undefined) {
			for (var x = 0; x < list.length; x++) {
				if (list[x].enabled()) {
					var tret;
					var cb = list[x].callback();
					if (cb != undefined) {
						ev.originalScope = this;
						if (list[x].legacy()) {
							tret = cb(ev);	
						}
						else {
							tret = cb.call((list[x].scope() != undefined ? list[x].scope() : this), ev, list[x]);
						}
					}
					if (ret != false && tret != undefined) {
						ret = tret;
					}
				}	
			}
			if (ev.returnValue != undefined) {
				return ev.returnValue;
			}
		}
		return ret;
	}
	
	
/*
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% EventMonitor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
	/**
	 *	EventMonitor
	 *	The event monitor class is used to track a single callback hook on an elements event handler
	 *
	 *	@param {Object} obj The object which is being monitored
	 *	@param {String} method The method which is being hooked 
	 *	@param {Function} callback The callback function to execute when the handler fires
	 *	@param {Boolean} legacy (Optional) If set to true, the arguments will not be normaized (browser independent)
	 *	@param {Object} scope (Optional) The object to set 'this' to before the call
	 *
	 *	@constructor
	 */
	function EventMonitor(obj, method, callback, legacy, scope) {
		this.i_obj = obj;
		this.i_method = method;
		this.i_callback = callback;
		this.i_legacy = legacy;
		this.i_enabled = true;
		this.i_scope = scope;
	}
	
	
	/**
	 *	Get/Set the scope of this listener.  This will be the value which 'this' is set to.
	 *
	 *	@param scope (Optional) The new scope of this listener
	 *
	 *	@return the current scope
	 */
	EventMonitor.prototype.scope = function(scope) {
		if (scope != undefined) {
			this.i_scope = scope;
		}
		return this.i_scope;
	}
	
	/**
	 *	Get/Set whether this callback should be treated as a legacy method.  Legacy methods will not have any
	 *	normalization done to maintain browser independence.  If this is set to true, it is assumed that the 
	 *	method being called will take care of any differences between supported browsers
	 *
	 *	@param state (Optional) The new legacy state of this event monitor
	 *
	 *	@return the current legacy state
	 */
	EventMonitor.prototype.legacy = function(state) {
		if (state != undefined) {
			this.i_legacy = state;
		}
		return this.i_legacy;
	}
	
	
	/**
	 *	Get/Set the callback method
	 *
	 *	@param callback (Optional) The new callback method
	 *
	 *	@return the current callback method
	 */
	EventMonitor.prototype.callback = function(callback) {
		if (callback != undefined) {
			this.i_callback = callback;
		}
		return this.i_callback;
	}
	
	/**
	 *	Get the method this object is monitoring
	 *
	 *	@return the string representation of the method this object is monitoring
	 */
	EventMonitor.prototype.method = function() {
		return this.i_method;
	}
	
	/**
	 *	Get the object this instance is monitoring
	 *
	 *	@return the object this instance is monitoring
	 */
	EventMonitor.prototype.parentObject = function() {
		return this.i_obj;
	}
	
	/**
	 *	Get/Set whether this handler is enabled.
	 *
	 *	@param state (Optional) The new enabled state for this handler
	 *
	 *	@return the current enabled state for this handler
	 */
	EventMonitor.prototype.enabled = function(state) {
		if (state != undefined) {
			this.i_enabled = state;
		}
		return this.i_enabled;
	}
	
	/**
	 *	Destroy this monitor, this will prevent any future callback executions.
	 *
	 *	@return true if the event listener was destroyed, false otherwise
	 */
	EventMonitor.prototype.destroy = function() {
		var av = this.parentObject().i_listeners[this.method()];
		if (av != undefined) {
			for (var x = 0; x < av.length; x++) {
				if (av[x] == this) {
					av.splice(x, 1);
					if (av.length == 0) {
						this.parentObject().i_listeners[this.method()] = undefined;
						var po = this.parentObject();
						po[this.method()] = null;
					}
					return true;
				}
			}
		}
		return false;
	}


