	/**
	 * @file
	 *   $Id: util.js,v 1.16 2007/06/19 21:04:51 cabernet Exp $
	 *
	 * @copyright
	 *   Copyright (c) 2006 Zerve, Inc.
	 * 
	 * Javascript Utility functions
	 * 
	 */

	function ZUtil( ) {

	}

	/**
	 * Returns the inner windth of of a window.
	 */ 
	ZUtil.prototype.getInnerWidth = function( ) {

		var x;
		if (self.innerHeight) // all except Explorer
		{
			x = self.innerWidth;
		}
		else if (document.documentElement && document.documentElement.clientHeight)
		// Explorer 6 Strict Mode
		{
			x = document.documentElement.clientWidth;
		}
		else if (document.body) // other Explorers
		{
			x = document.body.clientWidth;
		}
		return x;

	}
	
	/**
	 * Returns the inner height of of a window.
	 */ 
	ZUtil.prototype.getInnerHeight = function( ) {

		var y;
		if (self.innerHeight) // all except Explorer
		{
			y = self.innerHeight;	
		}
		else if (document.documentElement && document.documentElement.clientHeight)
		// Explorer 6 Strict Mode
		{
			y = document.documentElement.clientHeight;
		}
		else if (document.body) // other Explorers
		{
			y = document.body.clientHeight;
		}
		return y;

	}

	/**
	* Add event handler to an element
	*
	* @param elm
	*  The element to which event is to be added to ex: window
	* @param evType
	*  Type of event to add ex: 'unload'
	* @param fn
	*  Reference to a function to execute once event fires
	*/
	ZUtil.prototype.addEvent = function( elm, evType, fn ) {
	
		var useCapture = false;
		
		// cross-browser event handling for IE5+, NS6 and Mozilla
		// By Scott Andrew
		if( elm.addEventListener ) {
	
			elm.addEventListener( evType, fn, useCapture );
	
		} else if( elm.attachEvent ) {
	
			var r = elm.attachEvent( 'on' + evType, fn );
			if( r ) {
				// Add to our cache so we can remove events during window unload
				if(! ZUtil._eventCache ) {
					return;
				}
				ZUtil._eventCache[ZUtil._eventCache.length] = { e: elm, eventType: evType, eventFn: fn };
			}
	
		} else {
		
			elm['on' + evType] = fn;
	
		}
	
	}

	/**
	* Remove event handler for an element
	*
	* @param elm
	*  The element for which to remove event
	* @param evType
	*  Type of event to remove ex: 'unload'
	* @param fn
	*  Reference to a function which we want to remove.
	*/
	ZUtil.prototype.removeEvent = function( elm, evType, fn ) {

		var useCapture = false;

		if( elm.detachEvent ) {

			elm.detachEvent( evType, fn );

		} else if( elm.removeEventListener ) {

			elm.removeEventListener( evType, fn, useCapture );

		}

	}
		
	/**
	 * For use inside an event handler.
	 * Returns the event's target element. 
	 * (As in the element handling the event).
	 * 
	 * @param e
	 *   The event object passed into the event handler
	 * @return Element
	 *   null is returned if there is no target element
 	 */
	ZUtil.prototype.getTarget = function( e ){

		var target;	

		if( !ZUtil.isSafari && window.event && window.event.srcElement ) { // IE

			target = window.event.srcElement;
			return target;

		} else if( e && e.target ) { // The rest
			target = e.target;
		
		}

		if ( !target ) {
			return null;
		}

		// In Safari there is a bug where the target is not the link but node under it.
		if( ZUtil.isSafari && target.nodeType == 3 ) {
			target = target.parentNode;
		}

		return target;

	}
	
	/**
	 * Shortcut for creating a closure which is a 
	 * function call on an object. This is most useful
	 * for preserve the this property after calling 
	 * context has changed.
	 *
	 * Here is a simple example of how this may be useful
	 *
	 * function User( ) {
	 *
	 *   var name = 'bob';
	 *   ZUtil.addEvent( document.getElementById( 'name' ), 
	 *                   'mouseover',
 	 *                   ZUtil.bind( this, this.displayName ) ); 
	 *
	 * }
	 *
	 * User.prototype.displayName = function( ) {
	 *
	 *   alert( this.name ); // this will display bob
	 *
	 * }
	 * 
	 * Note: If you want currentTarget from the event for IE add events by using the
	 *  bindForIEeventListener( )
	 
	 * @param o Object reference
	 * @param f Function reference
	 */
	ZUtil.prototype.bind = function( o, f ) { 
		return function( ){ 
			return f.apply( o, arguments ); 
		}
	}

	/**
	 * Does same thing as bind() except if the browser is IE the 
	 * element object passed as the first argument will be the 
	 * window.event object.
	 * 
	 * Also if the handler is set the old fashin way like so:
	 * 
	 *  link.onclick = ZUtil.bindForIEeventListener( this , this.onClick );
	 * 
	 * When the handler executes:
	 * ... onClick( e ) {
	 *    this.something; // The same object that this was bound to.
	 *    link = e.currentTarget; // Access to the link (the element on which the event was attached to).
	 * }
	 *
	 * @param o Object reference
	 * @param f Function reference
	 */
	ZUtil.prototype.bindForIEeventListener = function( o, f ) {
		return function( ){ 

			if(! window.event ){	
				// this is unexpected see if function is used correctly
				return;
			}

			var e = window.event;

			// In this context this should be the element on which the event happened
			e.currentTarget = this;

			// But here we call the function in a different context !
			return f.call( o, e );

		}		
	}
	
	/**
	 * Stop propagation of the event.
	 *
	 * Stops the event from bubling up.
	 *
	 * If called from within an event handler the event 
	 * will not be handled by any other event handlers
	 * that are set on element that contain the element
	 * for which the event handler is executing.
	 * 
	 * Note that ZUtil.addEvent always adds event handlers 
	 * in non-capture mode so you can be use that the event
	 * is bubbling up when calling this function.
	 * 
	 */
	ZUtil.prototype.stopPropagation =  function( e ) {

 		if( e.stopPropagation ) {
 			e.stopPropagation( );
 		} else {
 			e.cancelBubble = true;
 		}

 	}

	/**
	 * Stop the default action from taking place.
	 * 
	 * When called from within an event handler the
	 * default action of that event will not be performed.
	 * 
	 * For example this is a useful way to stop a link 
	 * from being followed when handling the click event
	 * on a link.
	 */
	ZUtil.prototype.preventDefault = function( e ) {
		if( window.event && !window.opera ){
			window.event.returnValue = true;
		} else {
			e.preventDefault();
		}
	}

	/**
	 * Get related target of the event.
	 * 
	 * The related target of an event is usually 
	 * necessary to know when handling a mouse over or a
	 * mouse out event. The related target provides
	 * the other event related to the event. For example
	 * in a mouse over event it will be the element from
	 * which the mouse is coming from.
	 */	
	ZUtil.prototype.getRelatedTarget = function( e ) {
	
		var reltg = e.relatedTarget;
		if( !reltg ) {
			if( e.type == "mouseout" ) {
				reltg = e.toElement;
			} else if( e.type == "mouseover" ) {
 				reltg = e.fromElement;
			}
		}

		return reltg;

	}
	
	// We need to create one copy of the Util object	
	var ZUtil = new ZUtil( );

	var ua = navigator.userAgent.toLowerCase( );
	
	ZUtil.isIE = !window.opera && ua.indexOf('msie') != -1;
	ZUtil.isGecko = ( ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1 );
	ZUtil.geckoVer = parseInt( ua.substring( ( ua.lastIndexOf('gecko/') + 6 ), ( ua.lastIndexOf('gecko/') + 14 ) ) );
	ZUtil.isFx1_0 = ( ua.indexOf( 'firefox' ) != -1 && parseFloat( ua.substring( ua.lastIndexOf( 'firefox/' ) + 8, ua.lastIndexOf( 'firefox/' ) + 11 ) ) <= 1.0 );
	ZUtil.isSafari = ua.indexOf('safari') != -1;

	ua = null;
	
	if( ZUtil.isIE ) {
	
		// Attemp to fix the IE memory leak
		ZUtil._eventCache = new Array;
		window.attachEvent( 'onunload', _zutil_event_cleanup );

	}
	
	// This function is only used for IE
	function _zutil_event_cleanup( ) {

		if(! ZUtil._eventCache ) { return; }
		
		for( var i = 0; i < ZUtil._eventCache.length; i++ ) {

			if(! ZUtil._eventCache[i] ) { continue; }
			
			if( ZUtil._eventCache[i].e && ZUtil._eventCache[i].e.detachEvent ) {
				ZUtil._eventCache[i].e.detachEvent( ZUtil._eventCache[i].eventType , ZUtil._eventCache[i].eventFn );
			}
			ZUtil._eventCache[i].eventFn = null;
			ZUtil._eventCache[i].e = null;

		}

		ZUtil._eventCache = null;

	}
