/**
 * Create http loader to request data from server
 *
 * @param cb Callback function or object with keys 'object', 'method', ['errorhandler']
 */
function it_http(cb)
{
	this.instance = it_http.instances++;
	this.callback = cb ? cb : {};
	this.req = null;
	this.scrpt = [];
	this.callid = 0;
	this.busy = false;
	
	// register global reference
	it_http['__inst' + this.instance] = this;
}

/* Methods */
it_http.prototype = {

/* send GET request and trigger callback */
get: function(url, callback)
{
	if (typeof callback != 'undefined')
		this.callback = callback;
	this.send(url, 'GET');
},

/* send POST request with data and trigger callback */
post: function(url, data, callback)
{
	if (typeof callback != 'undefined')
		this.callback = callback;

	var postdata = '';
	if (typeof data == 'object') 
	{
		for (var k in data)
			postdata += (postdata ? '&' : '') + it_url_encode(k) + "=" + it_url_encode(data[k]);
	}
	else
		postdata = data;

	this.send(url, 'POST', postdata);
},

/* private method that finally sends the request */
send: function(url, method, postdata)
{
	this.stop();
	
	this.busy = true;
	this.req = null;
	var samehost = (!url.match(/^(\w+:)?\/\//) || url.indexOf(window.location.hostname) > 0);

	if (samehost) // use XMLHTTP request only if on same host
	{
		try
		{
			this.req = new XMLHttpRequest();
		}
		catch (e)
		{
			var classnames = [ 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' ];

			for (var i=0; i < classnames.length; i++)
			{
				try
				{
					this.req = new ActiveXObject(classnames[i]);
					break;
				}
				catch (e) { }
			}
		}

		try
		{
			this.req.open(method, url);
			var me = this;
			this.req.onreadystatechange = function() { me.ready_state_changed(); }
			var workingxmlhttp = this.req.onreadystatechange;

			if (!workingxmlhttp)		/* Old Konqueror */
				this.req = null;
		}
		catch (e) { }
	}

	this.starttime = new Date().getTime();

	if (this.req)
	{
		if (method == "POST")
			this.req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		this.req.send(postdata);
	}
	else
	{
		url += (url.match(/\?/) ? "&" : "?") + "itjs_call=it_http.__inst" + this.instance + "&itjs_callid=" + (++this.callid) + (postdata ? '&' + postdata : "");

		if (samehost || (window.opera && !window.XMLHttpRequest))	 // Opera 7 only works with iframes
		{
				var scrpt = document.createElement("iframe");
				scrpt.style.width = scrpt.style.height = 1;
				url += "&itjs_iframe=1";
		}
		else
		{
			var scrpt = document.createElement("script");
			this.req = { starttime: this.starttime };
			try
			{
				this.scrpt[this.callid] = scrpt;
				if (!document.all) scrpt.src = url;
				document.body.appendChild(scrpt);
				if (document.all) scrpt.src = url;
			}
			catch (e) { return false; }
		}
	}

	return true;
},

ready_state_changed: function()
{
	var req = this.req; // Avoid race conditions

	if (req && !req.aborted && req.readyState == 4)	// Check aborted flag because IE9 throws error c00c023f when accessing aborted request
	{
		var data = null;

		try
		{
			if (req.responseText != "")
				data = eval("(" + req.responseText + ")");
		}
		catch (e)
		{
			// trigger error handler (if defined)
			if (typeof this.callback == 'object' && this.callback.errorhandler)
			{
				var obj = this.callback.object ? this.callback.object : window;
				if (typeof obj[this.callback.errorhandler] == 'function')
					obj[this.callback.errorhandler](req.responseText);
			}
			else
				ED(e, req.responseText);
		}

		if (data)
			this.dataReady(data, this.callid);

		this.unlink(this.callid);
	}
},

dataReady: function(data, callid)
{
	var fixkonqueror33gcbug = this.req;
	var loadtime = new Date().getTime() - this.starttime;

	this.req = null;

	if ((typeof data == "object") && (this.callid == callid))
	{
		data.loadtime = loadtime;
		
		// trigger callback function
		if (typeof this.callback == 'function')
			this.callback(data);
		else if (typeof this.callback == 'object' && this.callback.method)
		{
			// it_set(data, this.callback);
			var obj = this.callback.object ? this.callback.object : window;
			if (typeof obj[this.callback.method] == 'function')
				obj[this.callback.method](data);
		}
	}
},

stop: function()
{
	try {
		this.req.aborted = true;	// Set aborted flag as IE9 throws error c00c023f when accessing aborted request
		if (this.req.readyState >= 2)	// Do not abort request never used before as it can throw error e.g. on Firefox
			this.req.abort();
	} catch (e) { }

	this.unlink(this.callid);
},

unlink: function(callid)
{
	if (this.req)
		this.req = null;

	if (this.scrpt[callid])
	{
		if (!(document.all && String(navigator.userAgent).indexOf('MSIE 5.0') > 0))
			document.body.removeChild(this.scrpt[callid]);
		this.scrpt[callid] = null;
	}

	this.busy = false;
} /* NO COMMA */

}


// static properties
it_http.instances = 0;

// static methods
it_http.get_instance = function()
{
	var inst;
	for (var i=0; i < it_http.instances; i++)
		if ((inst = it_http['__inst'+i]) && inst.pub && !inst.busy)
			return inst;
	
	inst = new it_http();
	inst.pub = true;
	return inst;
}

/* send GET request and trigger callback */
it_http.get = function(url, callback)
{
	var inst = it_http.get_instance();
	inst.callback = callback;
	inst.get(url);
}

/* send POST request and trigger callback */
it_http.post = function(url, postdata, callback)
{
	var inst = it_http.get_instance();
	inst.callback = callback;
	inst.post(url, postdata);
}