// Majax [Multi Ajax].
// -----------------------------------------------------------------------------
// Summary: Allows us to run simultaneous ajax requests and flexibly process
//          the returned data
//
// Notes  : You can over-ride what happens when the data is retrieved by creating a 
//          'process_data' method on the object, eg: 
//	    my_obj.process_data = function(x){alert(x)};
//          This means that you should be able to integrate the ajax_object 
//          with most of your pre-existing code.
//
// Bugs   : There may potentially be a memory problem
//          as we arent clearing/destroying the objects that are created atm.
// -----------------------------------------------------------------------------

var ajax_array = new Array;

function ajax_object(){
	// Define the values
	this.loading_msg  = "Data is currently loading, please wait.";
	this.loading_flag = 0;

	// Define the methods
	this.update_id              = update_id;
	this.get_update_id          = get_update_id;
	this.is_loading             = is_loading;
	this.set_start_time         = set_start_time;
	this.set_end_time     	    = set_end_time;
	this.calculate_loading_time = calculate_loading_time;
	this.get_url	            = get_url;
	this.post_data		    = post_data;
	this.state_changed          = state_changed;
	this.GetXmlHttpObject       = GetXmlHttpObject;
	this.destroy		    = destroy;
	this.process_javascript     = process_javascript;

	// Add ourselves to the ajax array and note our position
	ajax_array.push(this);
	this.position = ajax_array.length - 1;
}
function destroy(){
	// We dont need to do anything here right now.
}
function update_id(id){
	// Define the id of the area we want to insert
	// the returned value into
	this.area_id = id;
}
function get_update_id(){
	return(this.area_id);
}	
function is_loading(){
	return(this.loading_flag);
}
function set_start_time(){
	this.get_url_start_time = new Date();
}
function set_end_time(){
	this.get_url_end_time = new Date();
}
function calculate_loading_time(){
	return( ((this.get_url_end_time - this.get_url_start_time)/1000) );
}
function post_data(url,params){
	// Check to see if there is already data loading
	if(this.is_loading() == 1){
		alert(this.loading_msg);
	}
	else {
		this.set_start_time();
	}
	// Set the loading flag
	this.loading_flag = 1;

	// Define the method to be called when we have
	// received data.
	this.xml_obj=this.GetXmlHttpObject();

	// Open the connection
	this.xml_obj.open("POST", url, true);

	//Send the proper header information along with the request
	this.xml_obj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	this.xml_obj.setRequestHeader("Content-length", params.length);
	this.xml_obj.setRequestHeader("Connection", "close");

	// Send the parameters
	this.xml_obj.send(params);
}

function get_url(url){
	// Check to see if there is already data loading
	if(this.is_loading() == 1){
		alert(this.loading_msg);
	}
	else {
		this.set_start_time();
	}
	// Set the loading flag
	this.loading_flag = 1;

	// Define the method to be called when we have
	// received data.
	this.xml_obj=this.GetXmlHttpObject();

	// To avoid caching, append a random number
	// to the URL
	if(url.match(/\?/)){
	}
	else {
		// Append a ? otherwise it breaks the url
		url = url + "?1";
	}
	var unique_url = url + "&random=" + Math.random();

	// Log what URL is being loaded
	this.loading_url = unique_url;

	// Send the request
	this.xml_obj.open("GET", unique_url , true);
	this.xml_obj.send(null);
}
function state_changed(ajax_obj){
	// Deal with any changed state of the xml object
	var xml_obj = ajax_obj.xml_obj;
	var id = ajax_obj.get_update_id();
	if (xml_obj.readyState==4 || xml_obj.readyState=="complete"){
		if(ajax_obj.process_data){
			ajax_obj.process_data(xml_obj.responseText);
		}
		else{
			// Calculate the load time
			ajax_obj.set_end_time();
			var loading_time = ajax_obj.calculate_loading_time();
			var append = "<br>Loading time = " + loading_time + " seconds";
		
			// Add the data and append load time
			document.getElementById(id).innerHTML = xml_obj.responseText + append;

			// Now run any javascript thats inside the data
			if(ajax_obj.no_js==1){
				// You can set a no_js flag to avoid running js in the returned content
				// you may want to choose to do this if you are pulling back content
				// you did not write yourself.
			}
			else {
				process_javascript(xml_obj.responseText);
			}
	
			// Destroy the object
			ajax_obj.destroy();
		}
	}
}
function GetXmlHttpObject(){
	var obj_xml_http=null
	if (navigator.userAgent.indexOf('Opera')>=0){
		alert('This example doesnt work in Opera')
		return
	}

	// Create a custom handler
	// We need to do this because Microsoft
	// wont let us (easily) associate the object (this)
	// with the xml object
	// So we need to create a function to process any change
	// of state, but it needs to be unique, so to reference
	// the right object.
	// No doubt this is a hack and no doubt there is a better
	// way to do this.

	// Get the array num
	var array_num = this.position;

	// Create the handler method
	var eval_string = " \
		custom_handler = function state_changed_handler(){ \
			state_changed(get_ajax_object(" + array_num + ")); \
		}";
	eval(eval_string);
	
	// Check the browser type and set it all up
	if (navigator.userAgent.indexOf('MSIE')>=0){
		var strName='Msxml2.XMLHTTP'
		if (navigator.appVersion.indexOf('MSIE 5.5')>=0){
			strName='Microsoft.XMLHTTP'
		}
		try{
			obj_xml_http = new ActiveXObject(strName)
			obj_xml_http.onreadystatechange=custom_handler;
			return obj_xml_http
		}
		catch(e){
			alert('Error. Scripting for ActiveX might be disabled:' + e.description)
			return
		}
	}
	if (navigator.userAgent.indexOf('Mozilla')>=0){
		obj_xml_http = new XMLHttpRequest()
		obj_xml_http.onload   = custom_handler;
		obj_xml_http.onerror  = custom_handler;
		return obj_xml_http
	}
}
function get_ajax_object(x){
	// Return the ajax object from the array
	return(ajax_array[x]);
}
function process_javascript(content) {
	// This method takes data and runs any javascript
	// inside it, the javascript MUST be inside a fully formed
	// <script type="text/javascript"> tag.
	// This function is useful when your ajax object grabs
	// html with javascript inside.
        var search = content;
        var script;
        
        var is_singleq = 0; var singleq = "'";
        var is_doubleq = 0; var doubleq = '"';
        var is_escaped = 0; var escap = "\\";
        var layer = 0;
              
        while( script = search.match(/(<script[^>]+javascript[^>]+>\s*(<!--)?)/)) {
           search = search.substr(search.indexOf(RegExp.$1) + RegExp.$1.length);
           if (!(endscript = search.match(/((-->)?\s*<\/script>)/))) break;
           block = search.substr(0, search.indexOf(RegExp.$1));
           search = search.substring(block.length + RegExp.$1.length);
           
           while(func = block.match(/(function(.+?)\((.*?)\)\s*\{)/)) {
              eval(block.substr(0,block.indexOf(RegExp.$1)));
              // for evaluating non functions
              
              block = block.substr(block.indexOf(RegExp.$1) + RegExp.$1.length);
              name = RegExp.$2;
              param = RegExp.$3;
              
              is_singleq = 0;
              is_doubleq = 0;
              is_escaped = 0;
              layer = 0;
              
              
              for(i=0;i<block.length;i++) {
                 c = block.substr(i,1);
                 
                 if ((is_singleq || is_doubleq) && is_escaped) {
                    is_escaped = 0;
                 } else if (!is_doubleq && (c==singleq)) {
                    is_singleq = !is_singleq;
                 } else if (!is_singleq && (c==doubleq)) {
                    is_doubleq = !is_doubleq;
                 } else if ((is_singleq || is_doubleq) && (c==escap)) {
                    is_escaped = 1;
                 } else if ( c=="{") {
                    layer++;
                 } else if ( c=="}") {
                    if ( layer==0 ) {
                       break;
                    }
                    layer--;
                 }
              }
              
              code = block.substr(0,i-1);
              block = block.substr(i +1);
              
              code = code.replace(/\n/g, '\\n');
              code = code.replace(/\r/g, '\\r');
              code = code.replace(/'/g,"\\'");
              
              eval(name + " = new Function('"+param+"','"+code+"');");
           }
           eval(block); // for evaluating non functions
	}
}

