/* 
 * Copyright: 	(c) 2003 Autometa Corporation.  All Rights Reserved
 * Author: 		Rich Persaud
 * License:  	Lesser GNU Public License v2.1
 * Support:		http://autometa.com/dom
 * Version:		0.91, 2003-11-08
 */

function AM_domId ( p_domID )
{
	var _methodMaps				=	null								;
	var self					=	this								;

	if ( p_domID ) 
	{
		this.node		= 	document.layers ? 
								document[ p_domID ]
							  : document.all ? 
								document.all[ p_domID ] 
								: document.getElementById ?
									document.getElementById( p_domID )
									: null 								;
		if ( this.node )
		{
			this.style 			=	this.node.style 					;
			this.style.position	=	'absolute'							;
			this.style.fontSize	= 	'1px'								;
		}
		else
		{
			return null													;
		}
	}

	this.free = function ()
	{
		self.style 				=	null								;
		self.node 				=	null								;
		self.free 				=	null								;
	}

	return this															;
}

function AM_dom ( p_domID )
{
	var self		=	this												
	  , _ua 		=	navigator.userAgent.toLowerCase()					
	  , _dom		=	new AM_domId ( p_domID )								;

	self.node 		=	_dom.node												;

	     this.opera =  _ua.indexOf('opera') != -1								;
	if ( this.opera ) 
	{
		this.opera5 = (    _ua.indexOf("opera 5") != -1 
						|| _ua.indexOf("opera/5") != -1	)						;
		this.opera6 = (    _ua.indexOf("opera 6") != -1 
						|| _ua.indexOf("opera/6") != -1 )						;
		this.opera7 = (    _ua.indexOf("opera 7") != -1 
						|| _ua.indexOf("opera/7") != -1 )						;
	}
    else if ( _ua.indexOf('konqueror') != -1 )
        this.KH                 =   true                                ;
	else if ( defined( document.all	) && notDefined(  document [p_domID] ) )
		this.IE 				=	true										;
	else if ( defined( document.getElementById) )
		this.MZ 				=	true										;
	else if ( defined( document.layers) ) 
		this.NS 				=	true										;
	else 
		alert ('FIXME: dom id')													;

	function _mapItem ( p_map )
	{
		return (    '\n 		"self."       + ' + p_map + '.method		'
				 +	'\n	  +	" = function ("   + ' + p_map + '.arg  	+ ")" 	'
				 +	'\n	  +	"	{ "											'
				 +	'\n	  +	      " return "  + ' + p_map + '.code 	+ ";"	'
				 +	'\n	  +	"	};" 										'		
				 +  '\n   +		"self."       + ' + p_map + '.method + ".valueOf" '
				 +	'\n	  +	" = AM_fvalue2num;"									  '	);
	};

	eval ( AM_mapFactory ( '_EvalMaps' , _mapItem ) )							;
	var _w3c = new Object														;

	var _docBody				=	document.body								;
	if 		(    this.IE  	)
		_map 					=	new AM_map_dom_ie55()						;
	else if (	 this.MZ  
			  || this.KH
			  || this.opera7 )
	{
		_map 					=	new AM_map_dom_w3c( '_w3c' )				;
		_map.initHandlers ( _w3c )												;
	}
	else if ( 	 this.NS 	 )
		_map 					=	new AM_map_dom_ns4()						;
	else
	{
		return null																;
	}

	this.setCaptureHandlers =	function ( p_listVars, p_listDomEv ) 
	{
		var szEvalCap 			=	''											
		  , commands 			=	[ 'set' , 'release' ] 						
		  , _dN					=	_dom.node 									
		  , dummy_w3c			=	_w3c   										;

		for ( var i in p_listVars )
		{
			szEvalCap 			+=	  '\nvar ' + p_listVars[i].name 
									+ ' = p_listVars[' + i + '].obj;'			;
		}
		eval (szEvalCap)		// declare vars in local scope (for closure)	;

		for ( var i in commands )
		{
			var item															;
			szEvalCap 			+=	_map.capFactory ( commands[i] )				;
			for ( var j in p_listDomEv )
			{
				item			=	p_listDomEv[j]								;
				szEvalCap 		+= 	_map.capFactory ( item[0] , item[1] ) 		;
			}
			szEvalCap 			+=	_map.capFactory ( 'close' )					;
		}
		eval (szEvalCap)														;
	}
			
	function _freeMaps ( p_maps ) 
	{
		eval( AM_freeES ( p_maps, 'method' ) )							;
	}   

	this.free = function()
	{
		_freeMaps( _methodMaps )										;
		_docBody			=	null									;
		self.node.mxyCursor =	null									;
		self.style 			=	null									;
		self.node 			=	null									;
		self.free 			=	null									;
	}

	_EvalMaps( _map.methods )											;

	if ( this.KH ) 
	{
		this.idTimer 		=	291459									;
		this.oTimers 		=	new Object								;

		// Geneaology :: browser limitation identified 
		//				 by http://mojavelinux.com
		// override setTimeout for Konqueror
		this.setTimeout 	=	function ( p_closure , p_timeout )
		{
			this.idTimer++												;
			var _timer 		=	
			{
				callback 	:	p_closure   
			  ,	sysId		:   setTimeout 
								(  	
									'gAM_dom.getTimeout(' + this.idTimer + ')' 
								  , p_timeout  
								)   
			}															;
			eval ( 'this.oTimers.t' + this.idTimer + ' = _timer ;' )	;
			return this.idTimer 										;
		}																;

		this.getTimeout 	=	function ( p_idTimer )
		{
			eval (          'this.oTimers.t' + p_idTimer + '.callback();' 
				   + 'delete this.oTimers.t' + p_idTimer + ';'
				 )														;
			return this													;
		}																;

		this.clearTimeout 	=	function ( p_idTimer )
		{
			eval ( 'var sysId = this.oTimers.t' + p_idTimer + '.sysId;' );
			clearTimeout ( sysId ) 										;
			return this													;
		}																;

		this.elemClick		=	function ( elem )
		{
			if ( elem.onclick)
			{
				elem.onclick() 											;
			}
			else
			{
				if ( ! elem.target ) // no frames
					window.location.href 		=	elem.href 			;
				else
					elem.target.location.href 	=	elem.href 			;
			}
		}																;

		this.getSelection = function () { return '' }					;
	}																	

	return this															;

} // AM_dom()

function AM_map_dom ( p_method , p_code , p_arg )
{
	this.method				=	p_method								;
	this.code 				=	p_code									;
	this.arg 				=	p_arg 		|| ''						;
}

function AM_map_dom_w3c ( p_w3c )
{
	this.capFactory			= function ( p_event , p_domId )
	{
		if ( arguments.length == 1 )
		{
				 if ( p_event == 'set' )
			{
				this.capPrefix 		=	'addEventListener'								;
				return	'this.setCapture = function () {'								;
			}
			else if ( p_event == 'release')
			{
				this.capPrefix 		=	'removeEventListener'							;
				return	'this.releaseCapture = function () {'							;
			}
			else if ( p_event == 'close')
				return  '};'															;
		}
		else
			return ("document."  +  this.capPrefix 
					  + "( \'"  +  p_event  +  "\', " 
							    +  p_domId  +  "." +  p_event  +  " , false );"		)	;
	}																					;

	var _doClick 			=	function ( element )
	{
		var evt = element.ownerDocument.createEvent( "MouseEvents" )					;
		evt.initMouseEvent (
				'click' , true , true
			,	element.ownerDocument.defaultView
			,	1		,	0		,	0		,	0		,	0
			,	false	,	false	,	false	,	false
			,	0		,	null 	)													;
		element.dispatchEvent( evt )													;
	}																					;

	var _getBoundingClientRect = function ( p_domElem )
	{
		var cR 				= 	new Object												;
		cR.left 			=	getRealLeft ( p_domElem )								;
		cR.top 				=	getRealTop  ( p_domElem )								;
		cR.right			=	cR.left     + p_domElem.offsetWidth						;
		cR.bottom			=	cR.top 	    + p_domElem.offsetHeight					;
		return 					cR														;
	}																					;

	this.initHandlers 		=	function ( p_obj_w3c )
	{
		p_obj_w3c.doClick 					=	_doClick								;
		p_obj_w3c.getBoundingClientRect 	=	_getBoundingClientRect					;
	}

	this.methods			=	
	[
		new AM_map_dom ( 'curWidth'			,	'window.innerWidth'						)
	  , new AM_map_dom ( 'curHeight'		,	'window.innerHeight'					)
	  , new AM_map_dom ( 'docHeight'		,	'document.height'						)
	  , new AM_map_dom ( 'docWidth'			,	'document.width'						)
	  , new AM_map_dom ( 'scrollLeft'		,	'window.pageXOffset'					)
	  , new AM_map_dom ( 'scrollTop'		,	'window.pageYOffset'					)
	  , new AM_map_dom ( 'renderTop'		,	'0'										)
	  , new AM_map_dom ( 'getSelection'		,	'window.getSelection()' 				)
	  , new AM_map_dom ( 'getBoundingClientRect'	
											,	p_w3c + '.getBoundingClientRect( p_domElem )'
											,	'p_domElem'								)
	  , new AM_map_dom ( 'getElemById'		,	'document.getElementById( p_domElemId )'
											,	'p_domElemId'							)
	  , new AM_map_dom ( 'elemClick'		,	p_w3c + '.doClick( p_domElem )'
											,	'p_domElem' 							)
	  , new AM_map_dom ( 'setTimeout'		,	'setTimeout( p_closure, p_timeout )' 
										    , 	'p_closure , p_timeout' 				)
	  , new AM_map_dom ( 'clearTimeout'		,	'clearTimeout( p_timerId )' 
											, 	'p_timerId' 							)
	]																					;

	return this																			;
}

function AM_map_dom_ie55 ()
{
	this.capFactory 		= function ( p_event , p_domId )
	{
		if ( arguments.length == 1 )
			return ''																	;

		return  'document.on'      		  + p_event + '= function ( p_domE )'
			  + '{'
			  +             p_domId + '.' + p_event + '( p_domE ) ;'
			  + '};'																	;
	}																					;

	this.methods 			=
	[
		new AM_map_dom ( 'curWidth'			,	'_docBody.clientWidth'					)
	  , new AM_map_dom ( 'curHeight'		,	'_docBody.clientHeight'					)
	  , new AM_map_dom ( 'scrollLeft'		, 	'_docBody.scrollLeft'					)
	  , new AM_map_dom ( 'scrollTop'		, 	'_docBody.scrollTop'					)
	  , new AM_map_dom ( 'renderTop'		, 	'_docBody.scrollTop'					)
	  , new AM_map_dom ( 'docHeight'		,	'_docBody.scrollHeight' 				)
	  , new AM_map_dom ( 'docWidth'			,	'_docBody.offsetWidth' 					)
	  , new AM_map_dom ( 'setCapture'		,	'1'										)
	  , new AM_map_dom ( 'getSelection'		,	'document.selection.createRange().text' )
	  , new AM_map_dom ( 'releaseCapture'	,	'self.node.releaseCapture()'			)
	  , new AM_map_dom ( 'getBoundingClientRect'	
											,	'p_domElem.getBoundingClientRect()'
											,	'p_domElem'								)
	  , new AM_map_dom ( 'getElemById'		,	'document.getElementById( p_domElemId )'
											,	'p_domElemId'							)
	  , new AM_map_dom ( 'elemClick'		,	'p_domElem.click()'
											,	'p_domElem' 							)
	  , new AM_map_dom ( 'setTimeout'		,	'setTimeout( p_closure, p_timeout )' 
											, 	'p_closure , p_timeout' 				)
	  , new AM_map_dom ( 'clearTimeout'		,	'clearTimeout( p_timerId )' 
											, 	'p_timerId' 							)
	]																					;
	return this																			;
}

function AM_map_dom_ns4 ()
{
	this.methods			=	
	[
		new AM_map_dom ( 'getElemById'	,	'document.all[ p_domElemId ]'
										,	'p_domElemId'								)
	]																					;
	return this																			;
}

function AM_domEvent ( p_dom , p_event )
{
	if ( ! p_event )	
		   p_event 			= 	window.event 											;

	if 		( 	p_dom.IE	)
	{
		this.toElement			=	p_event.toElement 									;
		this.fromElement		=	p_event.fromElement									;
		this.srcElem 			=	p_event.srcElement 									;
		this.parElem 			=	this.srcElem.parentElement 							;
		if ( this.parElem )
			this.gparElem 		=	this.parElem.parentElement 							;
	}
	else 
	{
		if   ( p_event.type == 'mouseover' )
		{
			this.toElement		=	p_event.target										;
			this.fromElement	=	p_event.relatedTarget								;
		}
		else // mouseout
		{
			this.toElement		=	p_event.relatedTarget								;
			this.fromElement	=	p_event.target										;
		}
		this.srcElem 			=	p_event.target 										;
		this.parElem 			=	this.srcElem.parentNode								;
		if ( this.parElem )
			this.gparElem 		=	this.parElem.parentNode 							;
	}

	this.free = function ()
	{
		this.srcElem 			=	null												;
		this.parElem 			=	null												;
		this.gparElem 			=	null												;
		return 						false												;
	}

	return this																			;

} // AM_domEvent()

function AM_freeES ( p_freeList , p_prop ) 
{
	var	_itemES															;

	if ( ! p_freeList )
		return;

	if ( defined( p_prop ) )
	{
		_itemES 	= function ( pp_item ) 
		{ 
			var _methodName = eval ( 'pp_item.' + p_prop )		;
			return 'this.' + _methodName + ' = null;' 			; 
		}																;
	}
	else
		_itemES 	= function ( pp_item ) 
					  { return 'this.' + pp_item 	   + ' = null;'  ; };

	var _szEvalText	=	''												;
	var _item															;

	while ( _item = p_freeList.pop() )
	{
		_szEvalText += _itemES( _item )									;
	}

	return _szEvalText													;

} // AM_freeES() 

// Geneaology :: derived from technique at: http://devshed.com 
function AM_mergeOnload ( p_szLoad )
{
	if ( window.onload )
	{
		var szLoad 		=	window.onload.toString()							;
		
		var szMergeLoad	=  		p_szLoad + '();\n'								
							+	szLoad.substring(	szLoad.indexOf(     '{' ) + 1
												  , szLoad.lastIndexOf( '}' ) ) 
							+	';\n' 
		window.onload	=	new Function( szMergeLoad )							;
	}
	else
	{
		window.onload	=	eval( p_szLoad )									;
	}
} // AM_mergeOnload()

/*+-----------------------------------------------------------
  | AM_mapFactory()
  |_
    | Generate code to output (upon eval) 
    |  - a private mapper in the context of factory caller
    |   - to invoke a function parameter of this factory
    |	 - upon a map array parameter of the output mapper
    +---------------------------------------------------------*/

function AM_mapFactory ( 	p_szMapFactoryName
						  , p_fMapItem		  	)
{
	return (  p_szMapFactoryName + ' = function ( p_maps ) '
		+	'{					'
		+ 	'	if ( ! p_maps )	'
		+	'\n		return	;	'
		+	'\n	var map			'
		+	'\n   , szMapClosures = ""; ' 
		+ 	'\n	while ( map = p_maps.pop() )					'
		+	'\n	{												'
		+	'\n		szMapClosures += ' + p_fMapItem( 'map' ) + ';'
		+	'\n	}												'
		+	'\n	eval ( szMapClosures )					;		'
		+	'}												;	')				;

} // AM_mapFactory()

function getRealLeft( p_el ) 
{
    var _xPos 		= p_el.offsetLeft
      , _tempEl 	= p_el.offsetParent				;

    while ( _tempEl != null )
	{
        _xPos 		+=	_tempEl.offsetLeft			;
        _tempEl 	 =	_tempEl.offsetParent		;
    }
    return _xPos									;
}

function getRealTop( p_el ) 
{
    var _yPos 		= p_el.offsetTop
      , _tempEl 	= p_el.offsetParent				;

    while ( _tempEl != null )
	{
        _yPos 		+=	_tempEl.offsetTop			;
        _tempEl 	 =	_tempEl.offsetParent		;
    }
    return _yPos									;
}

function AM_fvalue2num ()
{ 	return this()									; };

// Geneaology :: technique from http://crockford.com
function notDefined ( testObj )
{   return ( typeof(testObj) == 'undefined' )       ; } 

function defined ( testObj )
{   return !( typeof(testObj) == 'undefined' )      ; }
