
function Ajax()
{
	this._polling = false;
	this._timeoutId = 0;
	this._commands = new Array();
	
	this._currentEventRequest = null;
	this._currentCommandRequest = null;
	this._containerId = null;
	
	this.onEvent = new Array();
	
	this.userId = 0;
	this.pollingSpeed = 5; // poll every 5 seconds for new events.

	// this is the default exception handler
	this.onException = _showException;
	this.onTrace = _showTracer;
}

//	Start polling for events
Ajax.prototype.start = function()
{
	this._polling = true;
	this.getEvents();
}

// Stop polling for events
Ajax.prototype.stop = function()
{
	if(this._timeoutId > 0)
	{
		window.clearTimeout(this._timeoutId);
		this._timeoutId = 0;
	}
	
	this.polling = false;
}

// Create a request
Ajax.prototype._createRequest = function()
{
	if(window.XMLHttpRequest)
	{
		return new XMLHttpRequest();
	}

	return new ActiveXObject("Microsoft.XMLHTTP");
}

// Poll for events. 
Ajax.prototype.getEvents = function()
{
	if(this._timeoutId > 0)
	{
		window.clearTimeout(this._timeoutId);
		this._timeoutId = 0;
	}
	
	var request = this._createRequest();
	this._currentEventRequest = request;
	
	request.open("GET", "Event.ajax?id="+this.userId, true)
	request.onreadystatechange = _handleEvents;
	request.send(null);	
}

Ajax.prototype.createCommand = function(name)
{
	return new Command(name);
}

Ajax.prototype.createContainer = function()
{
	if(this._containerId == null)
	{
		var command = this.createCommand("AjaxContainer.Create");
		command.callback = _createContainer_callback;
		this.execute(command);
	}
}

// This function hadles events that are requested with getevents.
function _handleEvents()
{
	if(window.ajax._currentEventRequest.readyState == 4)
	{
		var response = window.ajax._currentEventRequest.responseXML;
		
		var events = response.element.childNodes;
		
		for(var i=0; i<events.length; i++)
		{
			if(events[i].nodeName == "event")
			{
				var eventName = events[i].getAttribute("name");
				var args = _parseAjaxData(events[i], false);
			
				if(window.ajax.onEvent[eventName])
				{
					window.ajax.onEvent[eventName](args);
				}
			}
		}

		if(window.ajax._polling)
		{
			window.ajax._timeoutId = window.setTimeout("window.ajax.getEvents()", window.ajax.pollingSpeed * 1000);
		}
	}
}

Ajax.prototype.execute = function(command)
{
	this._commands[this._commands.length] = command;
	
	if(this._commands.length == 1)
	{
		this._sendNextCommand();
	}
}

Ajax.prototype._sendNextCommand = function()
{
	var request = this._createRequest();
	this._currentCommandRequest = request;

	var formData = "ajcommand="+this._commands[0].name;
	
	if(this._containerId != null)
	{
		formData += "&ajcontainerid="+escape(this._containerId);
	}
	
	formData += "&ajparameters="+encodeURIComponent(this._commands[0].parameters.toSource());
	
	request.open("POST", "Command.ajax", true)
	request.onreadystatechange = _handleCommandResult;
	request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	request.send(formData);	
}

function Event(name)
{
	this.name = name;
	this.arguments = new Array();
}

function Command(name)
{
	this.callback = null;
	this.name = name;
	this.parameters = new Object();
	this.items = new Object();
}

function _handleCommandResult()
{
	if(window.ajax._currentCommandRequest.readyState == 4)
	{
		var response = null;
		
		if(window.ActiveXObject)
		{
			response = window.ajax._currentCommandRequest.responseXML;
		}
		else
		{
			var responseText = window.ajax._currentCommandRequest.responseText;
			var parser = new DOMParser();
			response = parser.parseFromString(responseText, "text/xml");
		}
		
		var code = parseInt(response.getElementsByTagName("code")[0].childNodes[0].nodeValue);
		var message = response.getElementsByTagName("message")[0].childNodes[0].nodeValue;
		
		var result = new Result(code, message);
		
		var jsdata = "";
		
		// Firefox interprets a very long tekst as multiple textnodes. So we have to
		// concatenate the values of all the textnodes together to get the jsdata.
		for(var i=0;i<response.getElementsByTagName("data")[0].childNodes.length;i++)
		{
			jsdata += response.getElementsByTagName("data")[0].childNodes[i].nodeValue;
		}
		
		result.data = eval(jsdata);
		
		var trace = response.getElementsByTagName("trace")[0].childNodes[0].nodeValue;
		
		if(trace == "True")
		{
			window.ajax.onTrace(window.ajax._commands[0], result);
		}		

		if(result.code < -10000 && window.ajax.onException != null)
		{
			window.ajax.onException(window.ajax._commands[0], result.data);
		}
		else if(window.ajax._commands[0].callback)
		{
			window.ajax._commands[0].callback(window.ajax._commands[0], result);
		}
		
		for(var i=1; i<window.ajax._commands.length; i++)
		{
			window.ajax._commands[i-1] = window.ajax._commands[i];
		}
		
		window.ajax._commands.length--;

		if(window.ajax._commands.length > 0)
		{
			window.ajax._sendNextCommand();
		}
	}
}

function _showException(command, exception)
{
	window.currentException = new Object();
	window.currentException.exception = exception;
	window.currentException.command = command;
	
	var exceptionWin = window.open("error.ajax","exceptionWin","toolbar=no,status=no,menubar=no,width=640,height=496,scrollbars=no,resizable=no");
	exceptionWin.focus();
}

function _showTracer(command, result)
{
	if(window.traceList == null)
	{
		window.traceList = new Array();
		var traceWin = window.open("trace.ajax", "traceWin", "toolbar=no,status=yes,menubar=no,width=640,height=550,scrollbars=no,resizable=yes");
		traceWin.focus();
	}
	
	var info = new Object();
	info.command = command;
	info.result = result;
	
	window.traceList[window.traceList.length] = info;
}

function _createContainer_callback(command, result)
{
	window.ajax._containerId = result.data.containerId;
	window.setInterval("_updateContainer()", 60000);
}

function _updateContainer()
{
	var command = window.ajax.createCommand("AjaxContainer.Update");
	command.parameters["ContainerId"] = window.ajax._containerId;
	window.ajax.execute(command);	
}

function Result(code, message)
{
	this.code = code;
	this.message = message;
	this.data = null;
}

window.ajax = new Ajax();

// This is an implementation of the object.toSource() method for browsers that don't have this
// method implementated.
if(Object.prototype.toSource == null)
{
	Array.prototype.toSource = function(recursive)
	{
		var source = "[";
		var separator = "";

		for(var i=0; i<this.length; i++)
		{
			source += separator + this[i].toSource(true);
			separator = ", ";
		}	
	
		return source + "]";					
	}

	String.prototype.toSource = function(recursive)
	{
		return "\""+this.split("\\").join("\\\\").split("\n").join("\\n").split("\"").join("\\\"")+"\"";
	}
	
	Number.prototype.toSource = function(recursive) { return this.toString(); }
	Boolean.prototype.toSource = function(recursive) { return this.toString(); }
	
	Date.prototype.toSource = function(recursive)
	{
		return "(new Date("+this.valueOf()+"))";
	}
	
	Object.prototype.toSource = function(recursive)
	{
		var source = "{";
		var separator = "";
		
		for(var item in this)
		{
			if(this[item] != null && typeof(this[item]) != "function")
			{
				source += separator + item + ":" + this[item].toSource(true);
				separator = ", ";
			}
		}
		
		source += "}";
		
		if(!recursive)
		{
			source = "("+source+")";
		}
	
		return source;
	}
}

Function.prototype._isFunction = true;