/**
 * Ajax JavaScript class
 *
 * Contains methods to create the XMLHttpRequest object and to call remote
 * functions and object methods.
 *
**/
function Ajax( mtd, handler, debug, displayErrors, addRequestVars)
{
	/*** Public vars ***/
	
	// Wartegrafik, die beim Aufruf von replaceAsync ausgegeben wird (wenn leer -> keine Grafik)
	this.async_image		= '/gfx/loading.gif';
	this.async_msg;
	
	/*** Private vars ***/
	
	this._method			= mtd;
	this._handler			= handler;
	this._debug				= debug;
	this._displayErrors		= displayErrors;
	this._addRequestVars	= addRequestVars;
	this._userid;
	
	this.msg = function( msg )
	{
		if (this.userid != 536)
			return;
		alert(msg);
	}
	
	this.execjs = function( text )
	{
		reg = '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)';
		var match = new RegExp(reg, 'img');
		var response = text.replace(match, '');
		var scripts  = text.match(match);
		match2 	= new RegExp(reg, 'im');    
		var arr = new Array(3)
		arr[0] = response
		arr[1] = scripts		
		arr[2] = match2		
		
		return arr;
	}
	
	/*** Public methods ***/

	/**
	 * Call remote function
	 *
	 * @param[in] func Name of remote function
	 * @param[in] params Parameters of local function which has been called
	**/
	this.call = function( func, params )
	{
		var data			= this._prepareData( func, params );
		var xmlHttpRequest	= this._getXmlHttpRequestObject();
		var finalData		= this._prepareXmlHttpRequest( xmlHttpRequest, params, data );
		xmlHttpRequest.send( finalData );
		
		if ( !this._paramsHaveCallbackFunction( params ) )
			return this._decodeResponse( xmlHttpRequest.responseText ).response;
	}

	this.getTagWithId = function( id )
	{
		var tag = document.getElementById(id);
		if ( !tag )
			alert("Tag with id '" + id + "' not found!");
		
		return tag;
	}
	
	this.replace = function( id, content )
	{
		var tag = ajax.getTagWithId(id);
		if ( !tag )
			return;
		
		tag.innerHTML = content;
	}
	
	this.replaceSync = function( id, func, params )
	{
		var parameters = new Array();
		
		for (var i = 2; i < this.replaceSync.arguments.length; ++i)
			parameters.push( this.replaceSync.arguments[i] );
		
		ajax.replace( id, ajax.call( func, parameters ) );
	}
	
	this.replaceAsync = function( id, func, params )
	{
		if ( this.async_image )
			sync_wait = '<img src="' + this.async_image + '" class="img_middle">&nbsp;';
		if ( this.async_msg )
			sync_wait += this.async_msg;
		if ( sync_wait )
			ajax.replace( id, sync_wait );
			
		var parameters = new Array();
		
		for (var i = 2; i < this.replaceAsync.arguments.length; ++i)
			parameters.push( this.replaceAsync.arguments[i] );
		
		parameters.push( function( content ) { ajax.replace( id, content ); } );
		
		ajax.call( func, parameters);
	}
	
	/**
	 * holt alle Elemente eines Formulars und gibt sie in einem assoziativen Array zurück
	 *
	 * @param[in]	Formularname oder Formular-Object
	 * @return		Object (assoz. Array)
	**/
	
	this.getFormData = function( form )
	{
		if ( typeof form == 'string' )
			form = js.e( form );
		
		if ( !form )
			return;
		
		// FCK-Editor Workaround
		this.updateTextFields();
			
		var parameters = new Object();
		
		for( i = 0; form.elements[i]; ++i ) 
		{	
			var element = form.elements[i];
			
			if ( element.name ) 
			{	
				var value = element.value;
				
				switch ( element.type ) 
				{
					case 'checkbox':
						if ( element.checked ) {
							value = element.value ? element.value : 'on';
						}
						else
							continue;
						
						break;
					
					case 'radio':
						if ( !element.checked )
							continue;
						break;
				}
				
				
				// Sonderbehandlung für Formularfelder 
				// mit nicht-assoziativen Arrays (z.B. 'var[]')
				if ( element.name.match(/\[\]$/) ) 
				{
					var name = element.name.replace(/\[\]$/, '');
					
					if ( ! parameters[name] )
						parameters[name] = new Array();
				
					
						
					if ( element.options ) 
					{
						for ( j = 0; element.options[j]; ++j )
							if ( element.options[j].selected )
								parameters[name].push( element.options[j].value );
					}
					else
					{
						
						if ( element.value && element.checked )
							parameters[name].push( element.value );
						else
							parameters[name].push( value );
					}
				}
				else
					parameters[element.name] = value;
			}
		}
		
		// Rückgabe
		return parameters;
	}

	/*** Private methods ***/

	/**
	 * Return instance of XMLHttpRequest class
	 *
	 * @return Object of XMLHttpRequest
	**/
	this._getXmlHttpRequestObject = function()
	{
		var xmlHttpRequest = false;

		if ( window.XMLHttpRequest ) {
			xmlHttpRequest = new XMLHttpRequest();
		}
		else if ( window.ActiveXObject ) {
			try {
				xmlHttpRequest = new ActiveXObject( "Msxml2.XMLHTTP" );
			}
			catch (e)
			{
				try {
					xmlHttpRequest = new ActiveXObject( "Microsoft.XMLHTTP" );
				}
				catch (e) {}
			}
		}
		
		// Override mime type if browser supports it (like Mozilla)
		if ( xmlHttpRequest.overrideMimeType ) {
			xmlHttpRequest.overrideMimeType( "text/json" );
		}

		return xmlHttpRequest;
	}

	/**
	 * Prepare XMLHttpRequest object
	 *
	 * @param[in] xmlHttpRequest XMLHttpRequest object
	 * @param[in] params Parameters of function or method which has been called
	 * @param[in] data Data which will be send
	 * @return Final data which will be send
	**/
	this._prepareXmlHttpRequest = function( xmlHttpRequest, params, data )
	{
		var callbackFunction = this._getCallbackFunction( params );
		var handler;
		var finalData;

		if ( this._method == 'GET' )
		{
			handler	= this._handler + '?' + data + '&' + this._addRequestVars;
			finalData = null;
		}
		else {
			handler	= this._handler;
			finalData = data + '&' + this._addRequestVars;
		}
//		ajax.replace('x', handler);
		xmlHttpRequest.open( this._method, handler, callbackFunction != null );
		
		if ( this._method == "POST" )
		{
			xmlHttpRequest.setRequestHeader( "Method",		  "POST " + this._handler + " HTTP/1.1" );
			xmlHttpRequest.setRequestHeader( "Content-Type",  "application/x-www-form-urlencoded" );
			xmlHttpRequest.setRequestHeader( "Content-Length", finalData.length );
		}

		xmlHttpRequest.onreadystatechange = function()
		{
			if ( xmlHttpRequest.readyState == 4 )
			{
				try
				{
					var response = ajax._decodeResponse( xmlHttpRequest.responseText );
					if (!response && ajax._displayErrors) {
						alert( "AJAX error:\n" + 'leere Antwort erhalten' );
						return;
					}
					else if (!response)
						return;
				}
				catch (e)
				{
					if (ajax._displayErrors)
						alert( "AJAX error:\nUnknown response from server!\n\n" + xmlHttpRequest.responseText );
					return;
				}
				if ( response.errorCode == 0 && callbackFunction != null ) {
					
					if ( ajax._debug ) {
						// Show client/server versions and whole server response before executing callback function
						alert( "AJAX debug info:\n\nServer response: " + xmlHttpRequest.responseText );
					}
					
					callbackFunction( response.response );
				}
				
				else if ( response.errorCode != 0 && ajax._displayErrors ) {
					alert( "AJAX error:\n" + response.errorMessage );
				}
			}
		}
		
		return finalData;
	}

	/**
	 * Do params include callback function?
	 *
	 * @param[in] params Parameters of function or method which has been called
	 * @return Returns true if params contain callback function
	**/
	this._paramsHaveCallbackFunction = function( params )
	{
		if ( typeof( params ) == "object" && params.length > 0 )
			return ( typeof( params[ params.length - 1 ] ) == "function" );
		
		return false;
	}

	/**
	 * Return callback function from params
	 *
	 * @param[in] params Parameters of function or method which has been called
	 * @return Callback function
	**/
	this._getCallbackFunction = function( params )
	{
		if ( this._paramsHaveCallbackFunction( params ) )
			return params[ params.length - 1 ];
		
		return null;
	}

	/**
	 * Prepare parameters
	 *
	 * @param[in] params Parameters of function or method which has been called
	 * @return Prepared parameters
	**/
	this._prepareParams = function( params )
	{
		var preparedParams = new Array();

		if ( typeof( params ) == "object" && params.length > 0 )
		{
			var end = this._paramsHaveCallbackFunction( params ) ? 1 : 0;
			
			for( var i = 0; i < params.length - end ; i++ )
				preparedParams.push( params[ i ] );
			
		}

		return preparedParams;
	}

	/**
	 * Prepare data
	 *
	 * @param[in] cls Class name or null
	 * @param[in] funcOrMtd Function name (if cls == null) or method name
	 * @param[in] params Parameters of function or method which has been called
	 * @return Prepared data
	**/
	this._prepareData = function( func, params )
	{
		var data = new Object();
		
		data[ "params" ]	= this._prepareParams( params );
		data[ "func" ]		= func;
		
		return "ajax=" + encodeURIComponent( JSON.stringify( data ) );
	}

	this._decodeResponse = function( responseText )
	{
		return JSON.parse( responseText );
	}
}
