/*
  Title:	Thirteenth Parallel Toolkit - Events Library - ALPHA Version
  Description:	Provides functionality for cross browser event listeners

  Creator:      Michael van Ouwerkerk Pupius <http://www.speedingrhino.com>
  Publisher:	Thirteenth Parallel <http://13thparallel.org>
  Date:         2005-02-02
  Rights:       Copyright (c)2002-2005 Thirteenth Parallel
                You are free to use the scripts for non-commercial projects,
		as long as you leave these copyright statements intact
*/

// Toolkit.Events
// See http://api.13thparallel.org/api/events/ for documentation.
//
// Contents:
//    addListener
//    removeListener
//    clearListeners
//    _prepareForListeners (private method)
//    _patchEvent (private method)
//    apply (function prototype)

if( !window.Toolkit ) alert( "Toolkit has to be included before Toolkit.Events." );

Toolkit.Events = {
	addListener : function( object, eventName, listener, thisObj ) {
		if( thisObj == null || thisObj == undefined ) thisObj = window;
		if( typeof object[ eventName + "listeners" ] == "undefined" ) this._prepareForListeners( object, eventName );
		var listeners = object[ eventName + "listeners" ];
		var setListener = true;
		for( var i = 0; setListener && i < listeners.length; i++ ) {
			if( listeners[ i ][ 0 ] == listener && listeners[ i ][ 1 ] == thisObj ) {
				setListener = false;
			}
		}
		if( setListener ) listeners[ listeners.length ] = [ listener, thisObj ];
		return false;
	},


	removeListener : function( object, eventName, listener, thisObj ) {
		if( thisObj == null || thisObj == undefined ) thisObj = window;
		var listeners = object[ eventName + "listeners" ];
		if( listeners ) {
			for( var i = 0; i < listeners.length; i++ ) {
				if( listeners[ i ][ 0 ] == listener && listeners[ i ][ 1 ] == thisObj ) {
					for( var j = i; j < listeners.length - 1; j++ ) {
						listeners[ j ] = listeners[ j + 1 ];
					}
					listeners.length--;
					break;
				}
			}
		}
		return false;
	},


	clearListeners : function( object, eventName ) {
		object[ eventName + "listeners" ] = [];
		return false;
	},


	_prepareForListeners : function( object, eventName ) {
		object[ eventName + "listeners" ] = [];
		if( typeof object[ eventName ] == "function" ) {
			object[ eventName + "listeners" ][ 0 ] = [ object[ eventName ], object ];
		}
		object[ eventName ] = function() {
			var i;

			// Copy the arguments array, because sometimes it's read-only.
			// If there are 0 arguments make sure the first argument becomes a reference
			// to the patched window.event object. If there is 1 argument and it's an event
			// object (as it should be), patch it as well.
			var argumentsCopy = [];
			for( i = 0; i < arguments.length; i++ ) argumentsCopy[ i ] = arguments[ i ];
			if( arguments.length == 0 && window.event ) {
				argumentsCopy[ 0 ] = Toolkit.Events._patchEvent( window.event, this );
			}
			else if( arguments[ 0 ] && typeof arguments[ 0 ] == "object"
									&& arguments[ 0 ].toString().search( /event/i ) != -1 ) {
				argumentsCopy[ 0 ] = Toolkit.Events._patchEvent( arguments[ 0 ], this );
			}

			// Make a copy of the listeners array and execute that, so it cannot be
			// modified during execution by addListener or removeListener calls.
			var listeners = this[ eventName + "listeners" ];
			var listenersCopy = [];
			for( i = 0; i < listeners.length; i++ ) listenersCopy[ i ] = listeners[ i ];
			for( i = 0; i < listenersCopy.length; i++ ) {
				listenersCopy[ i ][ 0 ].apply( listenersCopy[ i ][ 1 ], argumentsCopy );
			}
		};
	},


	_patchEvent : function( evt, currentTarget ) {
		if( !evt.target ) evt.target = evt.srcElement;
		if( !evt.currentTarget ) evt.currentTarget = currentTarget;
		if( typeof evt.layerX == "undefined" ) evt.layerX = evt.offsetX;
		if( typeof evt.layerY == "undefined" ) evt.layerY = evt.offsetY;
		if( typeof evt.clientX == "undefined" ) evt.clientX = evt.pageX;
		if( typeof evt.clientY == "undefined" ) evt.clientY = evt.pageY;
		if( !evt.stopPropagation ) {
			evt.stopPropagation = function() { this.cancelBubble = true; };
		}
		if( !evt.preventDefault ) {
			evt.preventDefault = function() { this.returnValue = false; };
		}
		return evt;
	},

	cancelEvents : function (evt) {
		evt = Toolkit.Events._patchEvent(evt);

		//cancel events from bubbling up
		if( evt.stopPropagation ) evt.stopPropagation();
		if( evt.cancelBubble == false ) evt.cancelBubble = true;
	}
}

// apply prototype - modified from http://youngpup.net/projects/dhtml/listener/listener.js
if( !Function.prototype.apply ) {
	Function.prototype.apply = function( thisObj, params ) {
		if( thisObj == null || thisObj == undefined ) thisObj = window;
		if( !params ) params = [];
		var args = [];
		for( var i = 0; i < params.length; i++ ) {
			args[ args.length ] = "params[" + i + "]";
		}
		thisObj.__method__ = this;
		var returnValue = eval( "thisObj.__method__(" + args.join( "," ) + ");" );
		thisObj.__method__ = null;
		return returnValue;
	};
}

// end
