//============================================================================================
//|||||||||||||||||||||||||||||||||| GLOBAL VARIABLES ||||||||||||||||||||||||||||||||||||||||
//============================================================================================
var __IO_PARAMS_POOL	= new Array();	// global {read-only} a pool of IO parameter objects
var __IO_FREE_IDXS		= new Array();	// global {read-only} a pool of array indexs. Use to allocate a free IFRAME/form/parameter slot
//============================================================================================
//|||||||||||||||||||||||||||||||||| IO CLASS DECLARATION ||||||||||||||||||||||||||||||||||||
//============================================================================================
function IO(){
	this.params					= new Object();
	this.params.url 			= null;
	this.params.method			= 'POST';
	this.params.callback_func 	= null;
	this.params.callback_arg	= null;
	this.params.blank_url		= '';
	this.params.query_string	= new Object();
}
//--------------------------------------------------------------------------------------------
IO.prototype.type = 'IO';
//--------------------------------------------------------------------------------------------
IO.prototype.set_url = function(_url){ 
	var success = 0;
	if(_url != '' && _url != void(0) && _url != null){
		this.params.url = _url; 
		success = 1;
	}
	return success;
}
//--------------------------------------------------------------------------------------------
IO.prototype.set_GET = function(){ this.params.method = 'GET'; return 1; }
//--------------------------------------------------------------------------------------------
IO.prototype.set_POST = function(){ this.params.method = 'POST'; return 1; }
//--------------------------------------------------------------------------------------------
IO.prototype.set_callback = function(_callback_func){
	var success = 0;
	if(_callback_func != '' && _callback_func != void(0) && _callback_func != null){
		var attrib_type = typeof(_callback_func);
		if(attrib_type.toLowerCase() == 'function'){
			this.params.callback_func= _callback_func;
			success = 1;
		}
	}
	return success;
}
//--------------------------------------------------------------------------------------------
IO.prototype.set_callback_arg = function(_callback_arg){
	// there's no limit to what can be passed to a user's callback function
	this.params.callback_arg = _callback_arg;
	return 1;
}
//--------------------------------------------------------------------------------------------
IO.prototype.set_blank_url = function(_url){
	// we have to hope that the user passes in a valid blank url;
	this.params.blank_url = _url;
	return 1;
}
//--------------------------------------------------------------------------------------------
IO.prototype.add_name_val_pair = function(_name,_val){
	var success = 0;
	if(_name != null && _name != void(0) && _name != '' && _val != null && _val != void(0)){
		this.params.query_string[_name] = _val;
		success = 1;
	}
	return success;
}
//--------------------------------------------------------------------------------------------
IO.prototype.flush_name_vals = function(){
	for(var i in this.params.query_string){ delete this.params.query_string[i]; }
	return 1;
}
//--------------------------------------------------------------------------------------------
IO.prototype.dispatch = function(){
	var is_new, success = 0;
	var pool_idx, params = null;
	var unique_id = new Date().getTime()+''+Math.floor(1000 * Math.random());
	var i,str,qs,name_val;

	// at the very minimum, a user must specify the url of the page to submit to
	// a callback function isn't might not be needed if the user doesn't need
	// any feedback about it's success or failure
	if(this.params.url != null){

		// either grab a free pool index, or add an index to the pool
		pool_idx = __IO_FREE_IDXS.pop();
		if(pool_idx == void(0)){ 
			pool_idx = __IO_PARAMS_POOL.push(1) - 1; 
			is_new = 1; 
		}

		// clone the parameter object, put it in the pool, and keep a reference to it
		params = __IO_PARAMS_POOL[pool_idx] = new _io_clone_obj(this.params); 

		// if we're submitting via POST, simply add/tack on our unique id and pool index to the response url
		if(params.method == 'POST'){
			if(params.url.indexOf('?') == -1){ params.url += '?'; }
			else{ params.url += '&'; }
			params.url += 'io_id=' + pool_idx + '&cache_killer=' + unique_id;
		}
		else{
			// if we're doing GET and the user has included a query string with
			// their response page, then we have to take it off, parse out the nave
			// value pairs, and send them via form fields, otherwise they'll be lost
			i = params.url.indexOf('?');
			if(i != -1){
				str = params.url.substr(i+1);
				params.url = params.url.substr(0,i);
				qs = str.split('&');
				for(i = 0; i < qs.length; i++){
					name_val = qs[i].split('=');
					params.query_string[_io_urldecode(name_val[0])] = _io_urldecode(name_val[1]);
				}
			}
			// send the unique id and io slot id through the form as well
			params.query_string['cache_killer'] = unique_id;
			params.query_string['io_id'] = pool_idx;
		}

		// the prepped io call is now ready to retrieve it's data
		_io_load_url(pool_idx,is_new);
		success = 1;
	}
	return success;
}
//============================================================================================
//|||||||||||||||||||||||||||||||||| IO HELPER FUNCTIONS |||||||||||||||||||||||||||||||||||||
//============================================================================================
function _io_load_url(pool_idx, is_new){
	var params, form = null;
	var i,n,v,str = '';
	if(document.body){
		params = __IO_PARAMS_POOL[pool_idx]; 

		if(is_new){
			_io_create_iframe(pool_idx);
			_io_create_form(pool_idx);
		}

		// get a reference to our form, and prep it for submital
		form = _io_get_form(pool_idx);
		form.action = params.url;
		form.method = params.method;

		// create the hidden form fields along with their names and values,
		// where any double quote characters are fixed
		for(i in params.query_string){ 
			n = i.toString().replace(/"/g, '&#34;');
			v = params.query_string[i].toString().replace(/"/g, '&#34;');
			str += '<input type="hidden" name="'+n+'" value="'+v+'">'; 
		}

		form.innerHTML = str + form.innerHTML;
	
		// the slight delay before submitting allows some browsers (observed in
		// Opera) to fully recognize and accept any newly created iframe or form
		setTimeout('_io_get_form("'+pool_idx+'").submit();',1);
	}
	else{ setTimeout('_io_load_url('+pool_idx+','+is_new+');',200); }
}
//--------------------------------------------------------------------------------------------
function _io_callback(_url,_doc){
	var pool_idx, form, params = null;
	var t;

	// try to parse out our pool index from the url
	t = _url.indexOf('io_id=');
	if(t != -1){
		_url = _url.substr(t+6);
		t = _url.indexOf('&');
		if(t != -1){ _url = _url.substr(0,t); }
		pool_idx = _url;
	}

	if(pool_idx != null){
		// execute the callback function. Always pass it the iframes document object, and the callback arguments that the user supplied
		params = __IO_PARAMS_POOL[pool_idx];
		if(params.callback_func){ params.callback_func(_doc, params.callback_arg); }

		// rollback the url history so the iframe goes to it's blank page. This prevents problems with the browser's back button 
		//if(window.history){ window.history.go(-1); }

		// do some cleanup. erase the parameter object, remove any form parameters, and free our index back to the pool
		__IO_PARAMS_POOL[pool_idx] = '';
		form = _io_get_form(pool_idx);
		if(form){ form.innerHTML = ''; }
		__IO_FREE_IDXS.push(pool_idx);
	}
}
//--------------------------------------------------------------------------------------------
function _io_get_form(_idx){
	var form = null;
	if(!form && document.getElementById){ form = document.getElementById('io_form'+_idx); }
	if(!form && document.forms){ form = document.forms['io_form'+_idx]; }
	if(!form){ form = document['io_form'+_idx]; }
	return form;
}
//--------------------------------------------------------------------------------------------
function _io_create_form(_id){
	// prepend the new html to the document body
	var style_str = 'margin:0px; padding:0px; position:absolute; visibility:hidden; top:0px; left:0px; width:0px; height:0px;';
	if(document.getElementById("io_components"))
	{
		change_html = document.getElementById("io_components");
	}else{
		change_html = document.body;
	}

	change_html.innerHTML = '<form id="io_form'+_id+'" name="io_form'+_id+'" method="POST" action="" target="io'+_id+'" style="'+style_str+'"></form>' + change_html.innerHTML;
	// return a reference to the new form 
	return _io_get_form('io_form'+_id);
}
//--------------------------------------------------------------------------------------------
function _io_create_iframe(_id){
	// prepend the new html to the document body
	var style_str = 'margin:0px; padding:0px; position:absolute; visibility:hidden; top:0px; left:0px; width:0px; height:0px;';
	var src_url = __IO_PARAMS_POOL[_id].blank_url;

	if(document.getElementById("io_components"))
	{
		change_html = document.getElementById("io_components");
	}else{
		change_html = document.body;
	}

	change_html.innerHTML = '<iframe name="io'+_id+'" id="io'+_id+'" src="'+src_url+'" width="0" height="0" style="'+style_str+'"></iframe>' + change_html.innerHTML;
}
//--------------------------------------------------------------------------------------------
// this function (which is actually a class) takes an object and makes a clone
// of it so that one doesn't have to worry about the contents of objects
// changing due to pass by reference. Ex. var myClone = new _io_clone_obj(someObj);
function _io_clone_obj(_obj){ 
	for(var i in _obj){ 
		var attrib_type = typeof(_obj[i]);
		if(attrib_type.toLowerCase() == 'object'){ this[i] = new _io_clone_obj(_obj[i]); }
		else{ this[i] = _obj[i]; }
	} 
}
//--------------------------------------------------------------------------------------------
function _io_urldecode(_str){
	// Javascripts' builtin unescape function almost does a proper url decoding,
	// but first, plus sign character codes (%2B) must go to plus signs (+), and
	// plus signs (+) must go to the character codes for spaces (%20)
	return unescape(_str.replace(/%2B/g,'|').replace(/\+/g,'%20').replace(/\|/g,'+'))
}
//============================================================================================
//|||||||||||||||||||||||||||||||||| STANDARDIZE ARRAYS ||||||||||||||||||||||||||||||||||||||
//============================================================================================
if(!Array.prototype.pop){
	Array.prototype.pop = function(){
		var last_val = this[this.length-1];
		this.length = Math.max(this.length-1,0);
		return last_val;
	}
}
//--------------------------------------------------------------------------------------------
if(Array.prototype.push && ([0].push(true)==true)){ Array.prototype.push = null; }
if(!Array.prototype.push){
	Array.prototype.push = function(){
		for(var i = 0; i < arguments.length; i++){ this[this.length] = arguments[i]; }
		return this.length;
	}
}
//============================================================================================
