
function XMLHTTP(server_url, readyStateFunction)
{
	this.version = '0.5.1';
	this.server_url = server_url; 		// the SERVER page URL to connect to IE ajax_server.php
	this.async = true;					// whether we're in syncronous mode or async (default)
	this.debug=0;						// debug turned off by default, to see your request/response do ajaxObj.debug=1
	this.throttle=1;					// this enables throttling by default so all your requests are in the proper order
	this.method = "POST";				// by default all requests are sent via POST to override just use ajaxObj.method="GET"; before your call
	this.req = null;					// the xmlhttprequest variable, starts off as null
	this.errors = new Array();			// array of errors generated
	this.headers = new Array();			// array of optional headers you may pass in
	this.callBack = '';					// the callback function, when the ajax request is sent, this is the function that will be called
	this.format = "JSON";				// by default JSON encoding is the expected format, to override: ajaxObj.format = "XML"; or ajaxObj.format="TEXT";
	this.queue = new Array();			// the queue that will handle the throttling requests to keep your stuff in sync
	this.queue_in_process = 0;			// the current index for the throttling array
	this.readyStateFunction = (readyStateFunction) ? readyStateFunction : this.responseHandler;
}

/**
* Method to create an XMLHTTP object
*@access private
*/
XMLHTTP.prototype.getXMLHTTP = function()
{
	// moz XMLHTTPRequest object
	if (window.XMLHttpRequest) {
		this.req = new XMLHttpRequest();
	}
	// IE/Windows ActiveX version
	else if (window.ActiveXObject){
		this.req = new ActiveXObject("Microsoft.XMLHTTP");
	} else {
		if(this.debug == 1) {
			this.showDebug("<BR>FATAL ERROR: Could not create XMLHTTPRequest Object!<BR>");	
		}
		return false;
	}
	return this.req;
}

/**
* Main API method to use for AJAX requests
* example: ajaxObj.call("id=1", myCallBackFunction, "GET"); // GET REQUEST
* example: ajaxObj.call(("id=1", myCallBackFunction); 		// POST REQUEST
*@access public
*@param string A url encoded string of data to send to the server
*@param string A callback function that the server will launch when the response is generated
*@param string Used by the response handler function to send back throttled requests, you won't need to worry about this param
*/
XMLHTTP.prototype.call = function(queryVars, userCallback, queue_request)
{
	var currentVars;
	var callback;
	this.fullUrl = '';

	
	if(this.throttle == 1 && queue_request != 'queue') {		// throttling keeps your requests in sync, so things aren't out of order
		this.add2Queue(queryVars, userCallback);	
	}
	
	
	if(this.queue_in_process == 0)
	{
		// get XMLHTTPRequest Object
		if(!this.getXMLHTTP())
		{
			return false;
		}
		
		if(this.throttle == 1) {
			this.queue_in_process = 1;
			var currentCall = this.queue.shift();	// get the current call to make
			currentVars = currentCall.queryVars;
			callback = currentCall.userCallback;
		} else {
			currentVars = queryVars;
			callback = userCallback;
		}
		this.callBack = callback;
		
		
		
		// set response handler, if none is set, use our default one
		this.req.onreadystatechange =  this.readyStateFunction;
	
		// check for JSON encoding
		if(this.format != 'JSON') {
			currentVars = currentVars+'&json=false';
		}
			
		// if get is used, append the query variables to the url string 
		this.full_url = (this.method == "POST") ? this.server_url : this.server_url + '?'+ currentVars;
		
		if(this.debug == 1) {
			this.showDebug("<BR>Current State:<BR>Server Page: "+this.server_url+"<BR>HTTP Method: "+this.method+"<BR>Encoding Format: "+this.format+"<BR>Query String: "+currentVars+"<BR>");
		}
		
		// open connection
		this.req.open(this.method, this.full_url, this.async);
		
		// set any optional headers
		if(this.headers)
		{
			for(var i in this.headers)
			{
				if(i != '') {
					this.req.setRequestHeader( i, this.headers[i]);
				}
			}
		}
		
		// send request
		if(this.method == 'POST') {
			this.req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			this.request = currentVars;
			this.req.send(currentVars);
		} else {
			this.req.send(null);
		}
	}
	
}

/**
* Default method for parsing the response from the server. It will try to eval the obj.method_to_call property and pass the native JS object
*/
XMLHTTP.prototype.responseHandler = function()
{
	// only if req shows "complete"
    if (ajaxObj.req.readyState == 4) {
        // only if "OK"
        if (ajaxObj.req.status == 200) {
			if(ajaxObj.req.responseText.indexOf('ajax_msg_failed') != -1) {
				ajaxObj.callBack(false);
				ajaxObj.showDebug("Fatal Error: mybic_server sent back ajax_msg_failed!<br/>");
			} else {
				if(ajaxObj.format == "JSON") {
				try {
	        	var myObject = eval( '(' + ajaxObj.req.responseText + ')' );
				
				// callback function we passed to the server to process the results
	        	ajaxObj.callBack(myObject);
				} catch(e) {
						ajaxObj.errors["An error occured while trying to post your request"];
						alert('an error occurred in your response function, not mybic related');
						ajaxObj.callBack(false);
				}
				} else if(ajaxObj.format == "XML") {
					// send the raw xml data to the callback function
					ajaxObj.callBack(ajaxObj.req.responseXML);	
				} else {
					
					ajaxObj.callBack(ajaxObj.req.responseText);
				}
			}

        }
		if(ajaxObj.debug == 1) {
				// STRIP HTML
				var str = ajaxObj.req.responseText.replace(/(\<)/gi, '&lt;');
				var str = str.replace(/(\>)/gi, '&gt;');
				ajaxObj.showDebug("<br/><b>HTTPResponse:</b><br/> "+str+"<br/>");
			}
		// reset the method, format, etc back to class defaults
		ajaxObj.restoreDefaults();
		// reset our queue and call
		ajaxObj.queue_in_process = 0;
		if(ajaxObj.queue.length > 0) {
			
			ajaxObj.call('','','queue');
		}
    }
}

/**
* This method will allow you to create a "command queue" so ajax requests are sent in order they were fired. 
* You will be able to keep your request/responses in order they were sent
*/
XMLHTTP.prototype.add2Queue = function(queryVars, userCallback)
{
	var addAjax = new Array();
	addAjax['queryVars'] = queryVars;
	addAjax['userCallback'] = userCallback;
	this.queue.push(addAjax);
}

/**
* Method called after callback function is called to return the class to a default state
*/
XMLHTTP.prototype.restoreDefaults = function()
{
	this.method = "POST";
	this.format = "JSON";	
	this.callback = "";
	
}

/**
* This method will allow you to get all your form fields in ONE magical step!
* right before your ajaxObj.call statement all you have to do is: var form_vars = ajaxObj.getForm('formid');
* that will loop through the form id you pass, and put all the form variables into your query string!
*@param string The ID of the form you wish to submit
*@return string An encoded query string, ready to send to the server
*/

XMLHTTP.prototype.getForm = function(formid)
{
	var formobj = document.getElementById(formid);
	var fields = new Array();
	var form_len = formobj.elements.length;
	for (var x = 0; x < form_len; x++) {
	switch(formobj.elements[x].type) {
	   case 'select-one':
	
		fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].options[formobj.elements[x].selectedIndex].value));
		break;
		case 'select-multiple':
		var obj = formobj.elements[x];
			for(var y=0; y < formobj.elements[x].options.length; y++) {
			   if(formobj.elements[x].options[y].selected) {
						if(formobj.elements[x].options[y].value == ''){
							fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].options[y].text));
						} else {
							fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].options[y].value));
						}
			   }
			}
		break;
		case 'radio':
			   if(formobj.elements[x].checked) {
					   fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].value));
			   }
        break;
		case 'checkbox':
			if(formobj.elements[x].checked) {
				fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].value));
			}
		break;
		default:
		// text, password, textarea, etc
		fields.push(encodeURIComponent(formobj.elements[x].name)+'='+encodeURIComponent(formobj.elements[x].value));
		break;
	}
	}
	var new_qstring = '&' + fields.join('&');
	return new_qstring;
}



/**
* This method will print debug information to a div with an id of "mybic"
* It will help you debug your ajax application
*/
XMLHTTP.prototype.showDebug = function(msg)
{
	if(document.getElementById('mybic_debug')) {
		document.getElementById('mybic_errs').innerHTML += msg;
	} else {
		// create element
		var deb = document.createElement('div');
		deb.id = 'mybic_debug';
		deb.style.border = "thin solid black";
		deb.style.backgroundColor = "#F9F0AE";
		deb.style.padding = "10px";
		deb.style.position='absolute';
		deb.style.top = 0;
		deb.style.left=0;
		deb.style.width="500px";
		
		deb.style.overflow="auto";
		deb.innerHTML += '<a href="#" onclick="document.getElementById(\'mybic_errs\').style.display = (document.getElementById(\'mybic_errs\').style.display==\'none\') ? \'\':\'none\';" >hide/show me!</a>';
		deb.innerHTML += '&nbsp;&nbsp;&nbsp;&nbsp;<a href="#" onclick="document.getElementById(\'mybic_errs\').innerHTML = \'\'; return false;">Clear</a>';
		deb.innerHTML += '&nbsp;&nbsp;&nbsp;&nbsp;<a href="#" onclick="document.getElementById(\'mybic_debug\').style.left = (parseInt(document.getElementById(\'mybic_debug\').style.left)+100)+\'px\';">Move Left</a>';
		deb.innerHTML += '&nbsp;&nbsp;&nbsp;&nbsp;<a href="#" onclick="document.getElementById(\'mybic_debug\').style.top = (parseInt(document.getElementById(\'mybic_debug\').style.top)+100)+\'px\';">Move Down</a>';
		
		var errs = document.createElement('div');
		errs.id = "mybic_errs";
		errs.innerHTML += msg;
		deb.appendChild(errs);
		if(document.body) {
			document.body.appendChild(deb);
		} else {
			document.lastChild.appendChild(deb);
		}
		
	}
}


