var tsEventManager = Class.create({
	initialize: function() {
		this.watching = new Array(); // Array of {Element:element, String:event, Function:listener, Function:onFire} objects
	},
	
	watch: function( element, event, onFire ) {
		if ( browser.isIE ) {
			// mouseenter and mouseleave are much more reliable in ie, so change the corresponding event to mouseover or mousenter
			if ( event == "mouseover" ) {
				event = "mouseenter";
			} else if ( event == "mouseout" ) {
				event = "mouseleave";
			}
		}
		var listener = this.fire.bindAsEventListener(this, element, onFire);
		element.observe(event, listener);
		this.watching.push({ element:element, event:event, listener:listener, onFire:onFire });
		
		return this.watching.length - 1; // index of observer
	},
	
	fire: function( event, element, onFire ) {
		var target = (window.event) ? element.srcElement : event.target;
		var relatedTarget = (event.relatedTarget) ? event.relatedTarget : element.toElement;
		
		switch ( event.type ) {
		case "mouseover":
			this.buttonMouseover( element, target, relatedTarget, onFire, event );
			break;
		case "mouseout":
			this.buttonMouseout( element, target, relatedTarget, onFire, event );
			break;
		case "mouseup":
			onFire(element, event);
			break;
		case "mousedown":
			onFire(element, event);
			break;
		case "mouseenter":
			onFire(element, event);
			break;
		case "mouseleave":
			onFire(element, event);
			break;
		default:
			onFire(element, event);
			break;
		}
	},
	
	buttonMouseover: function( element, target, relatedTarget, onFire, event ) {
		var isAlreadyInside = false;
		var rtarg = relatedTarget;
		if ( relatedTarget ) { // if false, mouse came from outside the screen or didn't have a previous target, so isAlreadyInside should stay false.
			try {
				if ( relatedTarget == element ) {
					// Mouse came from element, so it's already inside
					isAlreadyInside = true;
				} else {
					relatedTarget.ancestors().each( function( e ){
						if( e == element ) isAlreadyInside = true;
						// Mouse came from one of element's children, so it's already inside
					}, element, isAlreadyInside);
				}
			} catch( e ) {}
		}
		if ( !isAlreadyInside ) { onFire( element, event ); }
	},
	
	buttonMouseout: function( element, target, relatedTarget, onFire, event ) {
		var isStillInside = false;
		if ( relatedTarget ) { // if false, mouse left the screen and isStillInside should stay false.
			try{
			if ( relatedTarget == element ) {
				// Mouse left to element, so it is still inside
				isStillInside = true;
			} else {
				relatedTarget.ancestors().each( function( e ) {
					if( e == element ) isStillInside = true;
					// Mouse left to one of element's children, so it's still inside
				}, element, isStillInside);
			}
			} catch( e ) {}
		}
		if ( !isStillInside ) { onFire( element, event ); }
	},
	
	pauseListener: function( index ) {
		var observer = this.watching[index];
		Event.stopObserving(observer.element, observer.event, observer.listener);
	},
	
	resumeListener: function( index ) {
		var observer = this.watching[index];
		Event.observe(observer.element, observer.event, observer.listener);
	},
	
	clearAllListeners: function() {
		this.watching.each( function( e ) {
			// See initialize method for watching implementation
			Event.stopObserving(e.element, e.event, e.listener);
		});
	},
	
	clearListener: function(index) {
		var observer = this.watching[index];
		Event.stopObserving(observer.element, observer.event, observer.listener);
		this.watching.splice(index, 1);
	}
});
