// JsonRequest: multi-threaded ajax/json request handler
// callback function accepts two arguments- data, and request type
// VERSION 1.2 - removed instance name dependency, replaced with 'that' variable and closures, no global callback function anymore- per-request callbacks instead
function JsonRequest(){
	this.ecb = function(r){alert(r['message'] ? r['message'] : 'Error id: ' + r['error'])};
	this.threads = [];
};
JsonRequest.prototype.setErrorCallback = function(c){
	this.ecb = c; // callback function to be called each time the list is updated
};

// callback is called on the request response, after it has been converted from json text to a javascript object
JsonRequest.prototype.makeRequest = function(url, p, callback){
	var that = this, i;
	//console.log('makeRequest  ', callback, url);


	if (!p) p = null;
	
	url += (url.indexOf('?') > -1 ? '&' : '?') + 'json=1';
	
	
	//$('messages').innerHTML += url + '<br>';	
	
	
	// get idle (or new) thread
	if ((i = this.getThread()) === null)
		return false;
	r = this.threads[i];
	
	//console.log('thread: ',i);	
	
	
	// set up the request - if it fails, try getting a fresh request object and try again before aborting 
	try {
		r.open(p ? 'POST' : 'GET', url, true);
	}
	catch(err){
//		console.log('first attempt failed - trying a fresh (unused) request object', err);
		this.resetThread(i);
		i = this.getThread();
		r = this.threads[i];
		try {
			r.open(p ? 'POST' : 'GET', url, true);
		}
		catch(err){
//			console.log('second attempt failed - aborting', err);
			return false;
		}
	}
	
//	console.log('using thread ', i, r);
	
	// set up the post vars
	if (p){
		r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		r.setRequestHeader("Content-length", p.length);
		r.setRequestHeader("Connection", "close");
	}
	
	// set up the callback function
	if (typeof callback === 'function')
		r.onreadystatechange = function(){ 
			if (that.threads[i].readyState == 4){
				that.clearThread(i);
				callback(that.evalR(that.threads[i].responseText));
			}
		};
	else
		r.onreadystatechange = function(){
			if (that.threads[i].readyState == 4)
				that.clearThread(i); 
		};

	
	// send the request
	r.send(p);

	// return true- TODO: return false if request somehow fails...
	return true;
};
// sets a current request object to available
JsonRequest.prototype.clearThread = function(i){
	var that = this;
	setTimeout(function(){that.threads[i].busy = false;},2000);
};

// find an unused request object, or a new one if none available. If forceNew is true, always get a new object 
JsonRequest.prototype.getThread = function(forceNew){
	var i = (forceNew ? this.threads.length : 0);
	for (; i < this.threads.length; i++){
		//if (this.threads[i].readyState == 0 || this.threads[i].readyState == 4) return i;
		if (!this.threads[i].busy) break;
	}
	if (!this.threads[i])
		this.threads[i] = this.makeObj();
	
	this.threads[i].busy = true;	
	
	return this.threads[i] ? i : null;
};

// resets a thread (use this if the thread craps out somehow)
JsonRequest.prototype.resetThread = function(i){
	this.threads[i] = this.makeObj();
};

// create a new XMLHttpRequest object
JsonRequest.prototype.makeObj = function(){
	if (window.XMLHttpRequest) // Mozilla, Safari,...
		r = new XMLHttpRequest();
  else if (window.ActiveXObject) { // IE
    try {
        r = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
          r = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {}
  }}
		
	return r ? r : false;
};
JsonRequest.prototype.evalR = function(j){
	return j != '()' ? eval('(' + j + ')') : {};
};