//j0zf 2006.3.12
//ajax.parallel.js
//my normal ajax.js library barfed on parallel requests because there was only 1 request object
/**
 * METHOD I:   ajax_get_request( ajax_url, ajax_handler, set_loading_id, forget_previous_requests )
 *	-- this method uses XMLHttpRequest() and processes commands
 *
 * METHOD II:  ajax_post_request( ajax_url, ajax_data, ajax_handler, set_loading_id, forget_previous_requests )
 *	-- this method uses XMLHttpRequest() and processes commands
 *	-- this method is better than ajax_get_request() when submitting a large amount of data
 *	-- data should be in url encoded format with escape()'d values ( e.g. variable1=value1&another_var=someother+value )
 *
 * METHOD III: ajax_call_js( unique_element_id, src_url, allow_reload_flag )
 *	-- this method immediatly runs as javascript the returned data
 *
 * AJAX CGI RETURN COMMANDS:
 *	-- Format:  ajax command|cgi returned ajax data
 *	-- by default the "ajax command" is just the "element id" who's innerHTML will be replaced
 *	   by the "cgi returned ajax data" text or html.
 *
 * SPECIAL CGI RETURN COMMANDS:
 *	-- ajax_error : reports error string
 *		* if the "ajax_error" element id is available then it will replace it's innerHTML with
 *		  the error text "cgi returned ajax data".
 *		* if the "ajax_error" element id is not available then it will do an alert('cgi returned ajax data / error text');
 *	-- ajax_run_script : will eval('cgi returned ajax data / javascript');
 *
 */

//USED TO SYNCHRONIZE THE PARALLEL ARRAYS
var ajax_requests_count = 0;

//AN ARRAY THAT CONTAINS THE REQUESTED AJAX OBJECTS
var ajax_requests = new Array();

//KEEP TRACK OF HANDLERS SO WE DISPATCH THE CORRECT ONE
//parallel array to ajax_requests
var ajax_handlers = new Array();

function ajax_createRequestObject( ajax_handler )
{
	var i = ajax_requests_count++;
    var ajax_http;
    var browser = navigator.appName;

	//CREATE THE AJAX REQUEST OBJECT
	if( browser == "Microsoft Internet Explorer" && window.ActiveXObject )
	{
        ajax_http = new ActiveXObject("Microsoft.XMLHTTP");
    }
	else
	{
        ajax_http = new XMLHttpRequest();
    }

	//SETUP THE HANDLER DISPATCHER
	ajax_http.onreadystatechange = ajax_handler_dispatcher;

	//ADD THE HANDLER
	if( ajax_handler == null )
	{
		ajax_handlers[i] = ajax_handler_default;
	}
	else
	{
		ajax_handlers[i] = ajax_handler;
	}

	//ADD THE REQUEST OBJECT
	ajax_requests[i] = ajax_http;
    return ajax_http;
}

function ajax_handler_dispatcher()
{
	var i = 0;
	var ajax_http = null;
	var ajax_handler = null;

	if( ajax_requests_count < 1 ) return;

	for( i = (ajax_requests_count - 1); i >= 0; i-- )
	{
		if( ajax_requests[i] && ajax_handlers[i] && ajax_requests[i].readyState == 4 )
		{
			ajax_http = ajax_requests[i];
			ajax_requests[i] = null;
			ajax_handler = ajax_handlers[i];
			ajax_handlers[i] = null;

			if ( ajax_http.status == 200 )
			{
				//alert( 'RESPONSE TEXT:[' + ajax_http.responseText + ']' );
				ajax_handler( ajax_http );
			}
			else if ( ajax_http.status == 403 && ajax_http.statusText == "Logged Out" )
			{
				window.location = 'login.php';
			}
			else
			{
				ajax_report_error( 'Ajax Error - Status Code: "' + ajax_http.status + '" Status Text: "' + ajax_http.statusText + '".' );
			}
		}
	}
}

//FORGET ALL PREVIOUS AJAX REQUESTS
function ajax_forget_requests()
{
	ajax_requests_count = 0;
	ajax_requests = new Array();
	ajax_handlers = new Array();
}

//VERY SIMPLE TO USE DEFAULT HANDLER
//CUSTOM HANDLERS CAN BE SPECIFIED WHEN MAKING THE REQUESTS
//Make requests by:
//  ajax_get_request( ajax_url, ajax_handler, set_loading_id, forget_previous_requests )
//  or
//  ajax_post_request( ajax_url, ajax_data, ajax_handler, set_loading_id, forget_previous_requests )
function ajax_handler_default( ajax_http )
{
	var sep_loc = ajax_http.responseText.indexOf( '|' );
	var response_name = '';
	var response_value = '';

	if( sep_loc > 0 )
	{
		response_name = ajax_trim_str( ajax_http.responseText.substr( 0, sep_loc ) );
		response_value = ajax_http.responseText.substr( 1 + sep_loc );

		if( response_name == 'ajax_error' )
		{
			//REPORT THE ERROR
			ajax_report_error( response_value );
		}
		else if( response_name == 'ajax_run_script' )
		{
			ajax_run_script( response_value );
		}
		else
		{
			//WRITE THE RESPONSE TO THE SPECIFIED ELEMENT
			if( ajax_set_value( response_name, response_value ) )
			{
				ajax_clear_error();
			}
			else
			{
				ajax_report_error( 'Error: Ajax Element Not Found (' + response_name + ').' );
			}
		}
	}
	else
	{
		ajax_report_error( 'Error: Invalid Ajax Response.' );
	}
}

function ajax_report_error( str )
{
	var ajerr = document.getElementById('ajax_error');
	if( ajerr )
	{
		ajerr.innerHTML = str;
	}
	else
	{
		alert( str );
	}
}

function ajax_clear_error()
{
	var ajerr = document.getElementById('ajax_error');
	if( ajerr )
	{
		ajerr.innerHTML = "";
	}
}

function ajax_run_script( str )
{
	eval(str);
}

function ajax_trim_str( str )
{
   str = str.replace(/^\s+/, '');
   str = str.replace(/\s+$/, '');
   return str;
}

/**
 * SET LOADING IMAGE
 */
function ajax_set_loading( loading_id )
{
	loading_id = document.getElementById( loading_id );
	if(loading_id)
	{
		loading_id.innerHTML = '<div class="ajax_loading_icon"><span class="ajax_loading_icon">Loading...</span></div>';
	}
}

/**
 * GET AN ELEMENTS VALUE.... Never mind the element's type...
 * -- add types as needed..
 * -- Not currently supported:
 *		- radio buttons
 *		- select tags with "multselect" enabled
 *		- and more...
 */
function ajax_get_value( element_id )
{
	var e = document.getElementById( element_id );
	var v = '';
	if( !e ){ return null; }

	switch( e.tagName.toUpperCase() )
	{
		case 'INPUT':
			switch( e.type.toUpperCase() )
			{
				case 'TEXT':
					v = e.value;
					break;
				case 'HIDDEN':
					v = e.value;
					break;
				case 'CHECKBOX':
					v = ( e.checked ? e.value : '' );
					break;
				default:
					v = e.value;
					break;
			}
			break;
		case 'TEXTAREA':
			v = e.value;
			break;
		case 'SELECT':
			v = e.options[ e.selectedIndex ].value;
			break;
		default:
			v = e.innerHTML;
			break;
	}

	return v;
}

/**
 * SET AN ELEMENTS VALUE.... Never mind the element's type...
 * -- add types as needed..
 */
function ajax_set_value( element_id, v )
{
	var e = document.getElementById( element_id );
	if( !e ){ return null; }

	switch( e.tagName.toUpperCase() )
	{
		case 'INPUT':
			switch( e.type.toUpperCase() )
			{
				case 'TEXT':
					e.value = v;
					break;
				default:
					e.value = v;
					break;
			}
			break;
		default:
			e.innerHTML = v;
			break;
	}

	return v;
}

/**
 * CALL A JAVASCRIPT FILE
 *	-- yes this can have a PHP or other CGI extension ( .js not required )
 *	-- Output will be ran as Javascript
 *
 *	unique_element_id : mangle away.. make it origninal to the page
 *	allow_reload_flag : if true then unique_element_id may be replaced by a new script load
 *
 */
function ajax_call_js( unique_element_id, src_url, allow_reload_flag )
{
	if( !allow_reload_flag && document.getElementById( unique_element_id ) )return;

	var head = document.getElementsByTagName('head').item(0);
	var script = document.createElement('script');
	script.src = src_url;
	script.type = 'text/javascript';
	script.language = 'javascript';
	script.id = unique_element_id;
	head.appendChild(script);
}

/**
 * USE "GET" METHOD TO MAKE HTTP REQUEST
 * ajax_handler : This is the function which will handle the request when retured as success
 * set_loading_id : (optional) This is the element id who's innerHTML will be replaced by the loading icon
 * forget_previous_requests : Destroys the handler queue before making request
 *
 */
function ajax_get_request( ajax_url, ajax_handler, set_loading_id, forget_previous_requests )
{
	if( !ajax_handler ){ ajax_report_error( 'Error: Invalid Ajax Handler Javascript Function.' ); return; }
	if( forget_previous_requests == true ){ ajax_forget_requests(); }
	if( set_loading_id && set_loading_id != '' ){ ajax_set_loading( set_loading_id ); }

	var ajax_http = ajax_createRequestObject( ajax_handler );

    ajax_http.open( 'get', ajax_url );
	ajax_http.send( null );
}

/**
 * USE "POST" METHOD TO MAKE HTTP REQUEST
 * ajax_data : Contains the POST data.
 *	-- this method is better than ajax_get_request() when submitting a large amount of data
 *	-- data should be in url encoded format with escape()'d values ( e.g. variable1=value1&another_var=someother+value )
 * ajax_handler : This is the function which will handle the request when retured as success
 * set_loading_id : (optional) This is the element id who's innerHTML will be replaced by the loading icon
 * forget_previous_requests : Destroys the handler queue before making request
 *
 */
function ajax_post_request( ajax_url, ajax_data, ajax_handler, set_loading_id, forget_previous_requests )
{
	if( !ajax_handler ){ ajax_report_error( 'Error: Invalid Ajax Handler Javascript Function.' ); return; }
	if( forget_previous_requests == true ){ ajax_forget_requests(); }
	if( set_loading_id && set_loading_id != '' ){ ajax_set_loading( set_loading_id ); }

	var ajax_http = ajax_createRequestObject( ajax_handler );

    ajax_http.open( 'post', ajax_url );
    ajax_http.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
	ajax_http.send( ajax_data );
}

/**
 * Ajax Handler that expects a JSON string in the response representing a JavaScript object
 * This function is intended to be an alternative to ajax_handler_default()
 * and handles multiple script/error/DOM-inserts
 * Parsing is done using an external JSON parser library (included) and thus
 * should not encounter security issues presented when using the simple eval() approach
 *
 * Each object member is the ID of the HTML element in the DOM (no error is displayed if not found)
 * Each object member's values will be placed into their respective HTML elements
 * Because there are multiple instances, this will not throw errors if
 *
 * - JonJon <jon@apogeeinvent.com> 2009.05.10
 */
function ajax_handler_JSON(ajax_http)
{
	// Legacy error handling found: go backward to ajax_handler_default()
	if ( ajax_http.responseText.match(/^\s*ajax_error\|/) )
	{
		return ajax_handler_default(ajax_http);
	}
	try
	{
		var obj = JSON.parse(ajax_http.responseText); // throws errors
		for ( var key in obj )
		{
			// An error occured, stop everything now!
			if ( key == "ajax_error" )
			{
				ajax_report_error(obj[key]);
				return;
			}
			// Found a run command
			else if ( key == "ajax_run_script" )
			{
				ajax_run_script(obj[key]);
			}
			// Insert into the DOM
			else
			{
				ajax_set_value(key, obj[key])
			}
		}
		ajax_clear_error();
	}
	catch ( e )
	{
		ajax_report_error("Error: Could not parse JSON response");
	}
}

/**
 * Ajax Handler that expects to do nothing and will do nothing
 *
 * - JonJon <jon@apogeeinvent.com> 2009-09-04
 */
function ajax_handler_noop() { }

