
//////////////////////////////////////////////////////////////////////////////////////////
//	debug fix
//////////////////////////////////////////////////////////////////////////////////////////
function checkDebug()
{

	Debug = function()
	{
		
	}
	Debug.send = function(str)
	{
		//alert (str);
	}

}


//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//	CLASS		DELEGATE
//
//	@author		Arjan van Wijk
//	@date		30-11-2005
//	@version	0.1
//	
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

function Delegate()
{
	
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION	CREATE
//
//	Delegates a function to another scope
//
//	@params		target: 	the target scope (Object)
//				function:	the target function (String)
//				args:		extra optional parameters (Mixed)
//
//	@Returns	the new function reference (Function)
//
//////////////////////////////////////////////////////////////////////////////////////////

Delegate.create = function(a_obj_target, a_str_func, args)
{
	// new array to store arguments
	var arr_delegateArguments = new Array();
	
	// get the arguments (all except the first two) (workaround for splice(2))
	for(var i=2; i<arguments.length; ++i) arr_delegateArguments[i-2] = arguments[i];
	
	// create the callBack function
	var f = function(args)
	{
		// new array to store arguments
		var arr_arguments = new Array();
		
		// get al current arguments (workaround for concat());
		for(var i=0; i<arguments.length; ++i) arr_arguments[i] = arguments[i];
		
		// push the delegate-arguments (workaround for concat/push)
		for(var i=0; i<arr_delegateArguments.length; ++i) arr_arguments[i + arguments.length] = arr_delegateArguments[i];
		
		// return the function
		return a_obj_target[a_str_func].apply(a_obj_target, arr_arguments);
	};
	
	// return the created callBack function
	return f;
}







//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//	CLASS		AJAX
//
//	@author		Arjan van Wijk
//	@created	29-11-2005
//	@changed	30-11-2005
//	@version	0.3.2
//	
//	@changelog
//
//	0.3.2 (Arjan | 12-12-2005)
//		- fixed undefined values
//
//	0.3 (Arjan | 30-11-2005)
//		- added callbacks for error, start, progress, init and status (incl. php parse errors)
//		- added function sendAndLoad(), send() now has no callBack
//		- added error handling for non-excisting callBackFunction
//
//	0.2 (Arjan | 30-11-2005)
//		- added static function for constructing the XmlHttpRequestObject (fix in IE)
//		- added function to set the server-side URL
//		- added function to fill the evt.value object (queryString variables from PHP)
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

function Ajax(a_url)
{
	checkDebug();
	Debug.send('new Ajax(' + a_url + ')');
	
	// url for server-side script
	this.str_url = a_url;
	// XmlHttpRequestObject for the data transfer
	this.xmlhttp = Ajax.getXmlHttpObject();
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	STATIC CONSTANTS
//
//////////////////////////////////////////////////////////////////////////////////////////

// synchroon and asynchroon
Ajax.ASYN = 1;
Ajax.SYN = 2;
// post and get
Ajax.POST = 4;
Ajax.GET = 8;

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION	GET_XML_HTTP_OBJECT
//	
//	Creates a new XmlHttpRequest Object
//
//	@returns	the created object (XmlHttpRequest)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.getXmlHttpObject = function()
{
	Debug.send('Ajax::getXmlHttpObject()');
	
	var xmlhttp = null;
	
	// Mozilla, Safari,...
	if (window.XMLHttpRequest)
	{
		xmlhttp = new XMLHttpRequest();
		
		if (xmlhttp.overrideMimeType)
		{
			//xmlhttp.overrideMimeType('text/xml');
		}
	}
	// IE
	else if (window.ActiveXObject)
	{
		try
		{
			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e)
		{
			try
			{
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e) {}
		}
	}
	
	
	return xmlhttp;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION	SEND
//	
//	sets the URL for the server side script
//
//	@params		url:	the url (String)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.setURL = function(a_url)
{
	Debug.send('Ajax::setURL(' + a_url + ')');
	
	this.str_url = a_url
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION	SEND
//	
//	Sends the attached variables via XmlHttpRequest
//
//	@params		mode: 	Bitsise Ajax.ASYN | Ajax.SYN | Ajax.POST | Ajax.GET
//						
//						Defaults are Ajax.ASYN and Ajax.POST
//						Use just one to change the type or method
//						Use both seperated by a | (OR)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.sendAndLoad = function(a_mode)
{
	this.send(a_mode, true);
}	

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUNCTION	SEND
//	
//	Sends the attached variables via XmlHttpRequest
//
//	@params		mode: 	Bitsise Ajax.ASYN | Ajax.SYN | Ajax.POST | Ajax.GET
//						
//						Defaults are Ajax.ASYN and Ajax.POST
//						Use just one to change the type or method
//						Use both seperated by a | (OR)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.send = function(a_mode, a_andLoad)
{
	Debug.send('Ajax::send(' + a_mode + ')');
	
	if(this.onState == null) this.onState = function() {};
	if(this.onStart == null) this.onStart = function() {};
	if(this.onProgress == null) this.onProgress = function() {};
	if(this.onInit == null) this.onInit = function() {};
	if(this.onError == null) this.onError = function() {};
	
	
	// used sendAndLoad() instead of send()
	this.doLoad = (a_andLoad == true) ? true : false;
	
	// array to store arguments that will be send over to php
	var arr_args = new Array();
	
	// set default vars (POST en ASYN)
	if(!(a_mode & (Ajax.ASYN | Ajax.SYN)))	a_mode |= Ajax.POST;
	if(!(a_mode & (Ajax.POST | Ajax.GET)))	a_mode |= Ajax.ASYN;
	
	// compose arguments in array
	for(var i in this)
	{
		var arg = this[i];
		
		// if function, skip!
		if(typeof(arg) == 'function') continue;
		
		// if class-property, like xmlhttp or str_url, skip!
		if(i == 'xmlhttp' || i == 'str_url' || i == 'doLoad' || i == 'onState' || i == 'onStart' || i == 'onProgress' || i == 'onInit' || i == 'onLoad' || i == 'onError') continue;
		
		// if array or object, construct querystring
		if(typeof(arg) == 'object')
		{
			arg = this.createStringFromArray(i, arg);
			arr_args.push(arg);
		}
		else
		{
			arr_args.push(i + '=' + arg);
		}
	}
	
	// split array into string
	var str_args = arr_args.join('&');
	Debug.send(str_args);
	
	// make GET vars
	if(a_mode & Ajax.GET)
	{
		Debug.send('Ajax::GET');
		var str_getURL = this.str_url + '?' + str_args;
		var str_postURL = null;
	}
	// make POST vars
	else
	{
		Debug.send('Ajax::POST');
		var str_getURL = this.str_url;
		var str_postURL = str_args;
	}
	
	Debug.send('Ajax::str_postURL : ' + str_postURL);
	Debug.send('Ajax::str_getURL : ' + str_getURL);
	
	if(a_mode & Ajax.ASYN) this.xmlhttp.onreadystatechange = Delegate.create(this, 'onSend');
	
	// send AJAX
	this.xmlhttp.open((a_mode & Ajax.GET) ? 'GET' : 'POST', str_getURL, a_mode & Ajax.ASYN);
	if(a_mode & Ajax.POST) this.xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	this.xmlhttp.send(str_postURL);
	
	
	if(a_mode & Ajax.SYN) this.onSend();
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUCNTION	ON_SEND
//
//	XmlHttp result object
//
//	@Returns	event Object (evt) with the following stucture:
//				type:			name of callBack function (String = 'onSend')
//				target:			reference to this object (Object)
//				responseText:	the responseText from the XmlHttpRequestObject (String)
//				responseXML:	the responseText from the XmlHttpRequestObject (XML)
//				value:			an Object with al the returned variables in &var=value& format (Object)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.onSend = function()
{
	// uninitialized | onStart
	if(this.xmlhttp.readyState == 0)
	{
		Debug.send('Ajax::onSendUninitialized(0)');
		this.onState({type: 'onState', target: this, state: this.xmlhttp.readyState, msg: 'Uninitialized'});
		this.onStart({type: 'onStart', target: this});
	}
	// loading | onProgress
	else if(this.xmlhttp.readyState == 1)
	{
		Debug.send('Ajax::onSendLoading(1)');
		this.onState({type: 'onState', target: this, state: this.xmlhttp.readyState, msg: 'Loading'});
		this.onProgress({type: 'onProgress', target: this});
	}
	// loaded
	else if(this.xmlhttp.readyState == 2)
	{
		Debug.send('Ajax::onSendLoaded(2)');
		this.onState({type: 'onState', target: this, state: this.xmlhttp.readyState, msg: 'Loaded'});
	}
	// interactive | onInit
	else if(this.xmlhttp.readyState == 3)
	{
		Debug.send('Ajax::onSendInteractive(3)');
		this.onState({type: 'onState', target: this, state: this.xmlhttp.readyState, msg: 'Interactive'});
		this.onInit({type: 'onInit', target: this});
	}
	
	// ready!
	if(this.xmlhttp.readyState == 4)
	{
		Debug.send('Ajax::onSendComplete(4)');
		this.onState({type: 'onState', target: this, state: this.xmlhttp.readyState, msg: 'Complete'});
		
		// info
		if (this.xmlhttp.status < 200)
		{
			this.onError({type: 'onError', target: this, status: this.xmlhttp.status, msg: 'Informational'});
		}
		// succesfull
		if (this.xmlhttp.status < 300)
		{
			// if parse error in php
			var error = this.xmlhttp.responseText.indexOf('<b>Parse error</b>: parse error') & this.xmlhttp.responseText.indexOf('.php</b> on line <b>')
			
			if(error == -1)
			{
				if(this.doLoad)
				{
					if(this.onLoad != undefined)
					{
						this.onLoad({type: 'onSend', target: this, responseText: this.xmlhttp.responseText, responseXML: this.xmlhttp.responseXML, value: this.createObjectFromQueryString(this.xmlhttp.responseText)});
					}
					else
					{
						this.onError({type: 'onError', target: this, status: 499, msg: 'Used sendAndLoad, and no onLoad callBack specified!'});
					}
				}
			}
			else
			{
				this.onError({type: 'onError', target: this, status: 599, msg: 'PHP Parse Error!'});
			}
		}
		// redirection
		else if (this.xmlhttp.status < 400)
		{
			this.onError({type: 'onError', target: this, status: this.xmlhttp.status, msg: 'Redirection'});
		}
		// client error
		else if (this.xmlhttp.status < 500)
		{
			this.onError({type: 'onError', target: this, status: this.xmlhttp.status, msg: 'Client Error'});
		}
		// server error
		else if (this.xmlhttp.status < 600)
		{
			this.onError({type: 'onError', target: this, status: this.xmlhttp.status, msg: 'Server error'});
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUCNTION	CREATE_STRING_FROM_ARRAY
//
//	Converts an array into a queryString
//
//	@params		name: 	name of the variable (String)
//				arr:	the array (Array)
//
//	@returns	the converted Array (String)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.createStringFromArray = function(a_name, a_arr)
{
	Debug.send('Ajax::createStringFromArray(' + a_name + ', ' + a_arr + ')');
	
	var arr = new Array();
	for(var i in a_arr)
	{
		//alert(i + ' : ' + a_arr[i]);
		// if array, recuse
		if(typeof(a_arr[i]) == 'object')
		{
			a_arr[i] = this.createStringFromArray(a_name + '__' + i, a_arr[i]);
			arr.push(a_arr[i]);
		}
		else if(a_arr[i] == undefined || a_arr[i] == null)
		{
			arr.push(a_name + '__' + i + '=' + '');
		}
		else
		{
			arr.push(a_name + '__' + i + '=' + a_arr[i].toString());
		}
	}
	
	// create queryString format
	var str = arr.join('&');
	
	return str;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
//	FUCNTION	CREATE_OBJECT_FROM_QUERY_STRING
//
//	Converts a queryString into an Object
//
//	@params		str: 	the queryString (String)
//
//	@returns	the converted queryString (Object)
//
//////////////////////////////////////////////////////////////////////////////////////////

Ajax.prototype.createObjectFromQueryString = function(str)
{
	// object to store properties
	var obj = new Object();
	
	// split variables from string
	var arr = str.split('&');
	
	// loop trough vars
	for(var i in arr)
	{
		// split in name:value pair
		var p = arr[i].indexOf('=');
		var key = arr[i].substr(0, p);
		var value = arr[i].substr(p+1);
		
		if(key == '' && value == '') continue;
		
		// set variable in object
		obj[key] = value;
	}
	
	//test
	//return 'test';
	
	// return object
	return obj;
}



//////////////////////////////////////////////////////////////////////////////////////////
//
//	USAGE
//
//////////////////////////////////////////////////////////////////////////////////////////

/*

// new object
var a = new Ajax('./ajax/getAjax.php');

// assign vars
a.var1 = 'test';
a.var2 = 345;
a.var3 = true;
a.var4 = new Array('narie', {een:12, twee:22, drie:[31, 32, 44]}, false);

// onState callBack
a.onState = function(evt)
{
	Debug.send('a::onState(' + evt.state + ', ' + evt.msg + ')');
}

// onStart callback
a.onStart = function()
{
	Debug.send('a::onStart()');
}

// onProgress callback
a.onProgress = function()
{
	Debug.send('a::onProgress()');
}

// onInit callback
a.onInit = function()
{
	Debug.send('a::onInit()');
}

// onLoad callback
a.onLoad = onKlaar;

// error callback
a.onError = function(evt)
{
	Debug.send('a::onError(' + evt.status + ', ' + evt.msg + ')');
}


// send
a.send(Ajax.ASYN | Ajax.GET);


// callback function
function onKlaar(evt)
{
	Debug.send('onKlaar : ' + evt);
	
	for(var i in evt)
	{
		Debug.send(i + ' : ' + evt[i]);
	}
	
	for(var i in evt.value)
	{
		Debug.send(i + ' : ' + evt.value[i]);
	}
}

*/
