
	/**
	 * AJAX transport class wrapping XMLHttpRequest
	 * 
	 * transport is capable of handling server callbacks like:
	 * 
	 * ajaxRefreshAllContainers{} - ignores single containerId and reloads all containers instead
	 * ajaxForceFullReload{http://myurl} - reloads the page instead of container insertion
	 * ajaxHideContainer{} - hides the current container (display none)
	 * ajaxJavascript{ myScript(); } - executes the javascript commands
	 */
	function AjaxTransport()
	{
		this.getXMLHTTP = function( url, singleContainerId )
		{
			var xmlHttp = false;
			
			// Internet Explorer
			try
			{
				xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e)
			{
				try
				{
					xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(e)
				{
					xmlHttp  = false;
				}
			}          
			
			// Mozilla, Opera und Safari
			if ( !xmlHttp && typeof XMLHttpRequest != 'undefined' )
			{
				xmlHttp = new XMLHttpRequest();
			}
			if ( xmlHttp )
			{
				xmlHttp.open( 'POST', url, true );
				xmlHttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;charset=utf-8' );
				xmlHttp.onreadystatechange = function ()
				{
					if ( xmlHttp.readyState == 4 
							&& xmlHttp.status == 200) //Complete
					{
						
						var body = document.getElementsByTagName( "body" )[0];
						//setting default cursor						
						body.style.cursor = "default";
						//remove curtain if visible
						ajaxShowCurtain(false);
						
						var oldAjaxContainers = document.getElementsByTagName( "div" );
						var responseText = xmlHttp.responseText;
						{
							var ajaxMethod = "ajaxRefreshAllContainers";
							var ajaxMethodPoint = responseText.indexOf( ajaxMethod );
							if( ajaxMethodPoint != -1 )
							{
								//reload full page
								var ajaxMethodParamStart = responseText.indexOf( "{", ajaxMethodPoint );
								var ajaxMethodParamEnd = responseText.indexOf( "}", ajaxMethodPoint );
								responseText = responseText.substring( 0, ajaxMethodPoint ) + 
									responseText.substring( ajaxMethodParamEnd + 1, responseText.length );
								singleContainerId = null;								
							}
						}
						
						var responseXML = document.createElement( "div" );
						responseXML.innerHTML = responseText;
						
						var isAnyNewCorrespondingContainerFound = false;
						var newAjaxContainers = responseXML.getElementsByTagName( "div" );
						
						var isOpera = navigator.appName.toLowerCase() == "opera";
						var isGecko = navigator.userAgent.toLowerCase().indexOf("gecko") != -1;
						
						for( var index in oldAjaxContainers )
						{	
							var oldContainer = oldAjaxContainers[index];
							if( oldContainer
									&& ( ( oldContainer.className != null
											&& oldContainer.className.toLowerCase().indexOf( "ajaxcontainer" ) != -1 )
										|| ( oldContainer.id != null
													&& oldContainer.id.toLowerCase().indexOf( "ajaxcontainer" ) != -1 )
										)
									|| ( singleContainerId != null 
											&& ( oldContainer.id == singleContainerId 
													|| oldContainer.id == (singleContainerId + "_tlc") ) ) //consider Top level elements (renamed id)										
								)
							{								
								for( var index2 in newAjaxContainers )
								{
									var newContainer = newAjaxContainers[index2];
									if( newContainer != null
											&& ( oldContainer.id == newContainer.id 
													|| oldContainer.id == (newContainer.id + "_tlc") ) //consider Top level elements (renamed id)
										)
									{
										isAnyNewCorrespondingContainerFound = true;
										//evaluate server callbacks
										var newContainerText = newContainer.innerHTML;
										{
											var ajaxMethod = "ajaxForceFullReload";
											var ajaxMethodPoint = newContainerText.indexOf( ajaxMethod );
											if( ajaxMethodPoint != -1 )
											{
												//reload full page
												var ajaxMethodParamStart = newContainerText.indexOf( "{", ajaxMethodPoint );
												var ajaxMethodParamEnd = newContainerText.indexOf( "}", ajaxMethodPoint );
												var url = newContainerText.substring( ajaxMethodParamStart + 1, ajaxMethodParamEnd )
												//alert( "reload: " + url );
												window.location.href = url; 
												return;
											}
										}										
										{
											var ajaxMethod = "ajaxHideContainer";
											var ajaxMethodPoint = newContainerText.indexOf( ajaxMethod );
											if( ajaxMethodPoint != -1 )
											{
												//reload full page
												var ajaxMethodParamStart = newContainerText.indexOf( "{", ajaxMethodPoint );
												var ajaxMethodParamEnd = newContainerText.indexOf( "}", ajaxMethodPoint );
												var newHTML = 
													newContainerText.substring( 0, ajaxMethodPoint ) + 
													newContainerText.substring( ajaxMethodParamEnd + 1, newContainerText.length );
												
												newContainer.innerHTML = newHTML;
												oldContainer.style.display = "none";
											}
										}										
										{
											var ajaxMethod = "ajaxJavascript";
											var ajaxMethodPoint = newContainerText.indexOf( ajaxMethod );
											if( ajaxMethodPoint != -1 )
											{
												//reload full page
												var ajaxMethodParamStart = newContainerText.indexOf( "{", ajaxMethodPoint );
												var ajaxMethodParamEnd = newContainerText.indexOf( "}", ajaxMethodPoint );
												var param = newContainerText.substring( ajaxMethodParamStart + 1, ajaxMethodParamEnd )
												var newHTML = 
													newContainerText.substring( 0, ajaxMethodPoint ) + 
													newContainerText.substring( ajaxMethodParamEnd + 1, newContainerText.length );
												
												newContainer.innerHTML = newHTML;
												window.setTimeout( param, 10 );
											}
										}
									
										//The "null" checks fail in Firefox, therefore using a browser check
										if ( isGecko
												|| !isOpera 
												|| ( newContainer != null 
														&& newContainer.children != null 
														&& newContainer.children.length > 0 )
											) 
										{
											//exchange containers
											_ajaxUpdateContent( oldContainer, newContainer );
										}
									}
								}
							}
						}
						//useless ajax response (different page?) -> sync lost, reload page
						if( !isAnyNewCorrespondingContainerFound )
						{
							//reload complete body content from response text 
							var lowerResponseText = responseText.toLowerCase();
							var bodyIndex = lowerResponseText.indexOf( "<body" );
							if( bodyIndex != -1 )
							{
								var bodyContentStartIndex = responseText.indexOf( ">", bodyIndex ) + 1;
								var bodyCloseIndex = lowerResponseText.indexOf( "</body", bodyContentStartIndex );						
								var responseBodyText = responseText.substring( bodyContentStartIndex, bodyCloseIndex );
								body.innerHTML = responseBodyText;
							}
						}
					}
				};
 				
				//setting wait cursor (clock)
				var body = document.getElementsByTagName( "body" )[0];
				if( body != null )
				{
					body.style.cursor = "wait";
				}
				return xmlHttp;
			}
			else
			{
				alert( "Your browser does not support XmlHttpRequest. Please use either Firefox 1.5, Internet Explorer 6.0, or Opera 9.0 or better." );
				return null;
			}
		}
		
		this.send = function( postURL, postValue, singleContainerId )
		{
			var xmlHTTP = this.getXMLHTTP( postURL, singleContainerId );
			xmlHTTP.send( postValue );
		}

	}
	
	function _ajaxUpdateContent( oldContainer, newContainer )
	{
		//exchange containers
		var firstChild;
		//clear old container
		while( (firstChild = oldContainer.firstChild ) != null )
		{
			oldContainer.removeChild( firstChild );
		}										
		//add new children to old container 
		while( (firstChild = newContainer.firstChild ) != null )
		{
			//alert(firstChild);
			newContainer.removeChild( firstChild );
			oldContainer.appendChild( firstChild );
		}
	}
	
	function getFunctionArgs( argumentArray, startPos )
	{
		var result = new Array();
		if( startPos == null )
		{
			startPos = 0;
		}
		if( argumentArray.length > startPos )
		{
			var firstArg = argumentArray[startPos];
			if( typeof(firstArg) == "object" ) 
			{
				return firstArg;
			}
			else 
			{
				for ( var i = 0; i < ( argumentArray.length - startPos ) / 2; i++ )
				{
					result[ argumentArray[i*2 + startPos] ] = argumentArray[i*2 + startPos+1];
				}
			}
		}
		return result;
	}
	
	/**
	 * submit a form with ajax
	 * @form id of the form to submit or the form node itself
	 * @singleContainerId may be null or not provided at all, if provided, only the specified AjaxContainer will be exchanged
	 * 
	 * you may provide additional parameters for the request by adding parameter pairs (, key, value, key, value ...) 
	 */
	function ajaxSubmit( idOrForm, singleContainerId /*optional*/ /*, paramsKey, paramValue ... */ )
	{
		ajaxSubmitAction( idOrForm, null, singleContainerId, getFunctionArgs( ajaxSubmit.arguments, 2 ) );
	}
	
	/**
	 * submit a form with ajax using a different action than provided in the form tag
	 * @form id of the form to submit or the form node itself
	 * @action different action to submit the form with
	 * @singleContainerId may be null or not provided at all, if provided, only the specified AjaxContainer will be exchanged
	 * 
	 * you may provide additional parameters for the request by adding parameter pairs (, key, value, key, value ...) 
	 */
	function ajaxSubmitAction( idOrForm, formAction, singleContainerId /*optional*/ /*, paramsKey, paramValue ... */ )
	{
		var form = null;
		if( typeof(idOrForm) == "string" )
		{
			form = document.getElementById( idOrForm );
			if( form == null
					|| form.id != idOrForm ) //ie hack with multiple forms
			{
				var forms = document.getElementsByTagName( "form" );
				for( var index in forms )
				{	
					if( forms[ index ].id == idOrForm )
					{					
						form = forms[ index ];
					}
				}
			}
		}
		else if( typeof(idOrForm) == "object" )
		{
			form = idOrForm;
		}
		
		if( form != null
				&& form.nodeName == "FORM" )
		{
			if ( typeof encodeURIComponent == "function" )
			{
				var postURL = form.action;
				if( formAction != null )
				{
					postURL = formAction;
				}
				var postValue = "isAjaxCall=1"; //extra parameter for ajax call tracking
				
				//transport form input elements 
				for ( var i = 0; i < form.elements.length; i++ )
				{
					var formElement = form.elements[i];
					if ( ( ( formElement.type == 'checkbox'
								|| formElement.type == 'radio' )
							&& formElement.checked )
						|| formElement.type != 'submit'
						|| formElement.type != 'text' )
					{
						if( postValue != "" ) postValue += '&';
						postValue += encodeURIComponent( formElement.name );
						postValue += '=';
						postValue += encodeURIComponent( formElement.value );
					}
				}
				
				//transport additional parameters (key - value pairs)
				var args = getFunctionArgs( ajaxSubmitAction.arguments, 3 );
				for ( var key in args )
				{
					if( postValue != "" ) postValue += '&';
					postValue += encodeURIComponent( key );
					postValue += '=';
					postValue += encodeURIComponent( args[key] );
				}
				
				if ( new AjaxTransport().send( postURL, postValue, singleContainerId  ) == false )
				{	
					form.submit();
				}
			}
			else
			{
				form.submit();
			}
		}
		else
		{
			alert( "AJAX: form to submit does not exist: " + idOrForm );
		}
	}
	
	/**
	 * to call from an anchor / link
	 * @url request url
	 * @singleContainerId may be null or not provided at all, if provided, only the specified AjaxContainer will be exchanged
	 * 
	 */
	function ajaxCall( url, singleContainerId )
	{	
		if ( typeof encodeURIComponent == "function" )
		{	 
			var postValue = "";
			if ( new AjaxTransport().send( url, postValue, singleContainerId  ) == false )
			{
				document.location.href = url;
			}
		}
		else
		{
			document.location.href = url;
		}
	}
	
	function ajaxClick( anchor, singleContainerId )
	{
		if( typeof(anchor) == "object" )
		{
			var url = anchor.href;
			ajaxCall( url, singleContainerId );
		}
		return false;
	}
	
	
	function ajaxShowCurtain( isVisible )
	{
		var body = document.getElementsByTagName( "body" )[0];
		var curtain = document.getElementById( "ajaxCurtain" );
		
		if( isVisible )
		{
			if( curtain == null )
			{
				//create on demand
				curtain = document.createElement( "div" );
				curtain.id = "ajaxCurtain";
				if( body != null )
				{
					body.appendChild( curtain );
				}
			}
			curtain.style.display = "block";
		}
		else if( curtain != null )
		{
			curtain.style.display = "none";
		}
	}