var XHR = {
	'xhr' : null,
	'busy' : false,
	'queue' : [],
	'newxhr' : function() {
		try { return new XMLHttpRequest(); }
		catch (e) {
			try { return new ActiveXObject('Msxml2.XMLHTTP'); }
			catch (e) {
				try { return new ActiveXObject('Microsoft.XMLHTTP'); }
				catch (e) {
					return null;
				}
			}
		}
	},
	'request' : function(source, url, fn, context, as_json) {
		if (this.busy) {
			XHR.queue.push(arguments);
			return false;
		}
		this.xhr = this.newxhr();
		XHR.request.callback = fn;
		XHR.request.context = context;
		var post_data = '';
		if (typeof source == 'object' && source.action) {
			// Assume source is an HTMLFormElement
			url = source.action;
			var form_el = null, el_val = null;
			for (var i = 0; i < source.elements.length; i++) {
				form_el = source.elements[i];
				if (!form_el.name || form_el.name.length < 1) continue;
				if (form_el.type == 'checkbox') if (!form_el.checked) continue;
				if (form_el.type == 'radio')
					el_val = Dom.radioGetValue(form_el);
				else
					el_val = ('_qd' in form_el && !form_el._qd || form_el.value == form_el.df ? '' : form_el.value);
				post_data += '&' + encodeURIComponent(form_el.name) + '=' + encodeURIComponent(el_val);
			}
		}
		else {
			// Assume source is an object with the post data
			var val;
			for (var key in source) {
			
				if (!source.hasOwnProperty(key)) continue;
				if (as_json && source[key].toJSONString && typeof source[key] != 'number' && typeof source[key] != 'string') {
					val = source[key].toJSONString();
				}
				else {
					val = source[key].toString();
				}
				post_data += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
			}
		}
		// Remove trailing ampersand
		if (post_data.length > 1) post_data = post_data.substr(1);

		// Send XHR request
		this.busy = true;
		this.xhr.open('POST', url, true);
		this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this.xhr.setRequestHeader('Content-Length', post_data.length);
		this.xhr.setRequestHeader('Connection', 'close');
		this.xhr.onreadystatechange = function() {
			if (XHR.xhr.readyState == 4) {
				// Check for redirection (@http://...)
				if (XHR.xhr.responseText.match(/^@http:\/\/.+/i)) {
					top.location.href = XHR.xhr.responseText.substring(1);
					XHR.busy = false;
					return;
				}
				// Otherwise pass to callback function
				if (typeof XHR.request.callback == 'function') {
					var result = null;
					try { result = eval('(' + XHR.xhr.responseText + ')'); }
					catch (e) { result = XHR.xhr.responseText; }
					XHR.busy = false;
					if (XHR.request.context) XHR.request.callback.call(XHR.request.context, result);
					else XHR.request.callback(result);
					if (XHR.queue.length > 0) XHR.request.apply(XHR, XHR.queue.shift());
				}
			}
		}
		this.xhr.send(post_data);
	}
};
// Dean Edwards/Matthias Miller/John Resig/Adam Saponara

function init() {
	// quit if this function has already been called
	if (arguments.callee.done) return;

	// flag this function so we don't do the same thing twice
	arguments.callee.done = true;

	// kill the timer
	if (_timer) clearInterval(_timer);

	// execute all functions in queue
	var exec = null;
	for (var i = 0, l = init.queue.length; i < l; i++) {
		exec = init.queue[i];
		exec.fn.apply(exec.context ? exec.context : this, exec.params)
	}
};

/* allow function references with parameters
   to be pushed to an init queue via
   init.add(fn, context, param1, param2, param3, etc) */
init.queue = [];
init.add = function(fn, context) {
	if (typeof fn != 'function') return;
	var args = [];
	for (var i = 2, l = arguments.length; i < l; i++) args.push(arguments[i]);
	init.queue.push({'fn': fn, 'context' : context, 'params' : args});
}

/* for Mozilla/Opera9 */
if (document.addEventListener) {
	document.addEventListener("DOMContentLoaded", init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
	document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
	var script = document.getElementById("__ie_onload");
	script.onreadystatechange = function() {
		if (this.readyState == "complete") {
			init(); // call the onload handler
		}
	};
/*@end @*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
	var _timer = setInterval(function() {
			if (/loaded|complete/.test(document.readyState)) {
			init(); // call the onload handler
		}
	}, 10);
}

/* for other browsers */
window.onload = init;

