/*

Versatile Ajax library

*/

if (typeof(debug) == "undefined")
{
	debug = false;
}

if (!window.XMLHttpRequest)
{
	window.XMLHttpRequest = function()
	{
		try
		{
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (error) {}
		
		try
		{
			return new ActiveXObject("Microsoft.XMLHTTP");
		} catch (error) {}
		
		return undefined;
	}
}

function Nestor()
{	
	this.options = {
		type:		"xml",
		method:		"GET",
		async:		true,
		encoding:	"UTF-8",
		headers:	{},
		handler:	null
	};
	
	this.queue = new Array();
	this.busy = false;
	this.requestObjectSync = null;
	this.requestObjectAsync = null;
	
	this.getRequestObject = function(async, forceNew)
	{
		var requestObjectName = "requestObject" + (async ? "Async" : "Sync");
		if (this[requestObjectName] === null || forceNew)
		{
			this[requestObjectName] = new XMLHttpRequest();
		}
			
		return this[requestObjectName];
	}
	
	this.sendRequest = function(url, options, data)
	{
		options = Object.extend(options || {}, this.options);
		
		var requestObject = this.getRequestObject(options['async'], options['async'] && !!window.opera);
		
		if (requestObject)
		{
			if (options['async'] && this.busy)
			{
				this.addToQueue(url, options, data);
			} else
			{
				if (options['async']) this.busy = true;
				
				url = createUrl(url, { output: options['type'].toLowerCase() });
				
				if (options['method'].toUpperCase() == "POST")
				{
					// encoding meegeven aan content-type als deze bekend is
					if (!("Content-Type" in options['headers']))
					{
						if (options.encoding)
						{
							options['headers']['Content-Type'] = options.contentType + "; charset=" + options.encoding;
						} else
						{
							options['headers']['Content-Type'] = options.contentType;
						}
					}					
				} else
				{
					// als het geen POST is... nou euh... dan is het een GET
					options['method'] = "GET";
					data = null;
				}
				
				requestObject.open(options['method'].toUpperCase(), url, !!options['async']);
				
				for (var header in options['headers'])
				{
					if (options['headers'].hasOwnProperty(header))
					{
						requestObject.setRequestHeader(header, options['headers'][header]);
					}
				}
				
				if (options['async'])
				{
					requestObject.onreadystatechange = this.handler.bind(this, options);
					requestObject.send(data);
				} else
				{
					requestObject.send(data);
					return this.handler(options);
				}
			}
			
			return true;
		}
		
		return false;
	}
	
	this.addToQueue = function(url, options, data)
	{
		var newJob = {
			url: url,
			options: options,
			data: data
		}
			
		this.queue.push(newJob);
		this.checkQueue();
	}
	
	this.checkQueue = function()
	{
		if (!this.busy && this.queue.length)
		{
			var request = this.queue.shift();
			this.sendRequest(request['url'], request['options'], request['data']);
		}
	}
	
	this.handler = function(options)
	{
		var result = null;
		var requestObject = this.getRequestObject(options['async']);
		
		if (requestObject.readyState == 4)
		{
			if (requestObject.status == 200)
			{
				switch (options['type'].toLowerCase())
				{
					case "xml":
						result = this.validateXML(requestObject.responseXML);
						break;
					case "json":
						result = this.parseJSON(requestObject.responseText);
						break;
					case "text":
					default:
						// text... ja, graag of niet hoor...
						result = requestObject.responseText;
						break;
				}
			
				if (options['handler'])
				{
					result = options['handler'](result);
				}
			}
				
			if (options['async'])
			{				
				requestObject.onreadystatechange = function() {};
				this.busy = false;
				this.checkQueue();
			}
		}
		
		return result;
	}
	
	this.validateXML = function(xmldata)
	{
		if (!xmldata)
		{
			if (debug)
			{
				alert("XML string is empty");
			}
			return false;
		}
		
		if (xmldata.documentElement)
		{
			return xmldata;
		} else if (xmldata.parseError)
		{
			if (debug)
			{
				alert("Error parsing XML data: \n\n" + xmldata.parseError.reason);
			}
		} else
		{
			if (debug)
			{
				alert("No XML data found");
			}
		}
		
		return false;
	}
	
	this.parseJSON = function(string)
	{
		try
		{
			if (/^("(\\.|[^\"\\\n\r])*"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+$/.test(string))
			{
				return eval('(' + string + ')');
			}
		} catch (error) {}
		
		if (!string)
		{
			if (debug) alert("JSON string is empty");
		} else
		{
			if (debug) alert("Invalid JSON response: \n\n" + string);
		}
		
		return false;
	}
}
