function JsRequest( )
{
	this.id = JsRequest.instances.length;
	
	this.jobs = [];
	this.onLoad = null;
	
	this.lastJobId = null;
	this.historyTrackerFrame = this.createInvisibleIframe( document.body );

/*
	this.lastHash = null;
	var self = this;
	setInterval( function() { self.detectLocationChange() }, 50 );
*/
	JsRequest.instances[ this.id ] = this;
}
JsRequest.HISTORY_TRACKER_URL = "historyTracker.html";
JsRequest.CALLBACK_QUERY_PARAMETER = "jscallback";

JsRequest.instances = new Array();

JsRequest.create = function()
{
	return new JsRequest();
}

JsRequest.parseQueryString = function( queryString )
{
	var querys = new Object();
	
	queryString = queryString.replace( /^\?/, "" );
	
	var variables = queryString.split( "&" );
	var parts;
	for( var i = 0; i < variables.length; i++ )
	{
		parts = variables[i].split( "=" );
		querys[ decodeURI( parts[0] ) ] = ( parts[1] ? decodeURI( parts[1] ) : '' );
	}
	
	return querys;
}

JsRequest.prototype.getStaticReference = function()
{
	return "top.JsRequest.instances['" + this.id + "']";
}

JsRequest.prototype.executeJob = function( job )
{
	this.lastJobId = job.id;
	
	// execute immediately...
	job.load();

	// ... but make sure it also gets loaded into the browser history (via an iframe)
	var url = JsRequest.HISTORY_TRACKER_URL + "?" + JsRequest.CALLBACK_QUERY_PARAMETER + "=" + this.getStaticReference() + ".loadJobById&jobId=" + job.id;
	this.historyTrackerFrame.src = url;
	
	return true;
}

JsRequest.prototype.loadJobById = function( jobId )
{
	if( this.jobs[ jobId ] && jobId != this.lastJobId )
		this.jobs[ jobId ].load();
}

JsRequest.prototype.createInvisibleIframe = function( parentNode )
{
	var iframe = document.createElement( "iframe" );
	iframe.style.width = '1px';
	iframe.style.height = '1px';
	iframe.style.position = 'absolute';
	iframe.style.top = '-10px';
	iframe.style.left = '-10px';
	iframe.style.zIndex = '1000';
	
	if( parentNode )
		parentNode.appendChild( iframe );
		
	return iframe;
}


/*
JsRequest.prototype.detectLocationChange = function()
{
	if( document.location.hash && document.location.hash != this.lastHash )
	{
		this.lastHash = document.location.hash;
		var jobId = parseInt( this.lastHash.replace('#', '') );
		if( !isNaN(jobId) && this.jobs[jobId] )
			//alert( jobId )
			this.jobs[jobId].load();
	}
}

JsRequest.prototype.changeHash = function( hash )
{
	//window.location.hash = hash;
	document.location.hash = hash;
	//document.location.href = document.location.pathname + '#' + hash;
}
*/

JsRequest.prototype.load = function(url, params)
{
	var job = new JsRequestJob(this, this.jobs.length, url, params);
	this.jobs.push(job);
	this.executeJob( job );
}

JsRequest.prototype.onJobLoad = function(job, returnValue)
{
	if(this.onLoad)
		this.onLoad(job, returnValue);
}



function JsRequestJob(loader, id, url, params)
{
	this.loader = loader;
	this.id = id;
	this.url = url;
	this.parameters = params;
	
	this.iframe = null;
}
JsRequestJob.instances = {};

JsRequestJob.prototype.getStaticReference = function()
{
	return "top.JsRequestJob.instances['"+this.id+"']";
}

JsRequestJob.prototype.load = function()
{
	JsRequestJob.instances[this.id] = this;
	
	this.iframe = this.loader.createInvisibleIframe( document.body );
	
	var url = this.url + (this.url.indexOf('?') == -1 ? '?' : '&') + JsRequest.CALLBACK_QUERY_PARAMETER + "=" + this.getStaticReference() + '.onLoad';
	this.iframe.src = url;
}

JsRequestJob.prototype.onLoad = function(returnValue)
{
	this.loader.onJobLoad(this, returnValue);
	if( this.iframe )
		document.body.removeChild(this.iframe);
}

