var RequestManager =(function(){
/*
LOOSELY GEBASEERD OP YAHOO UTIL,
GEMODIFICEERD NAAR PRIVATE SCOPE EN OBJECT LITERALS 
DOOR AALDERT VAN WEELDEN  JANUARI 2010
*/
/*
FORMAT :

RequestManager.submit({
				type 			: {string}, get of post
				url 			: {string} url vb:'validate.php?id='+t.id+'&value='+t.value+'&sid='+Math.random(),
				scope			: {string}[optioneel]
				data			: {string}postdata url-encoded
				onsuccess 		: {object} callback
				onfailure 		: {object} callback
				
			});

PROPERTIES oResponse object :

				oResponse.tId
				oResponse.status
				oResponse.statusText
				oResponse.getResponseHeader
				oResponse.getAllResponseHeaders
				oResponse.responseText
				oResponse.responseXML
				oResponse.data = oResponse.responseText  onsucces en oResponse.statusText onfailure
				
				
PUBLIC METHODS :

abort(o, callback, isTimeout)
 * @description Method to terminate a transaction, if it has not reached readyState 4.
   * @method abort
   * @public
   * @static
   * @param {object} o The connection object returned by asyncRequest.
   * @param {object} callback  User-defined callback object.
   * @param {string} isTimeout boolean to indicate if abort was a timeout.
   * @return {boolean}
   
getRefForm(FormId)
 * @description This method returns a reference to the indicated form
   * @method getRefForm
   * @public
   * @static
   * @param {string || object} form id or name attribute, or form object.


getFormElements(formId)
 * @description This method returns an object with references to all formelements
   * referenced by name
   * @method getFormElements
   * @public
   * @static
   * @param {string || object} form id or name attribute, or form object.

initHeader(label,value)
  * @description Public method that stores the custom HTTP headers for each transaction.
   * @method initHeader
   * @public
   * @static
   * @param {string} label The HTTP header label
   * @param {string} value The HTTP header value
   * @return {void}
   
isCallInProgress(o)
  * Public method to check if the transaction is still being processed.
   *
   * @method isCallInProgress
   * @public
   * @static
   * @param {object} o The connection object returned by asyncRequest
   * @return {boolean}
   
setDefaultPostHeader(b)
  * @description Member to enable or disable the default POST header.
   * @method setDefaultPostHeader
   * @public
   * @static
   * @param {boolean} b Set and use default header - true or false .
   * @return void
   
getForm(formId,query)
 * @description This method assembles the form label and value pairs and
   * constructs an encoded string.
   * submit() will automatically initialize the
   * transaction with a HTTP header Content-Type of
   * application/x-www-form-urlencoded.
   * @method getForm
   * @public
   * @static
   * @param {string || object} form id or name attribute, or form object.
   * @param {string} optional , returns a single field as name/value pair.

setField(name,value,oForm)
 * @description This method sets the value of a given formelement.
   * @method setField
   * @public
   * @static
   * @param {string || object} field id  or field object.
   * @param {string || object} optional , the desired value of the field.
   * @param {string} optional , if omitted, the default form is used
   
setPollingInterval(i)
   * @description Member to modify the default polling interval.
   * @method setPollingInterval
   * @public
   * @static
   * @param {int} i The polling interval in milliseconds.
   * @return void

setProgId(id)
  * @description Member to add an ActiveX id to the existing xml_progid array.
   * In the event(unlikely) a new ActiveX id is introduced, it can be added
   * without internal code modifications.
   * @method setProgId
   * @public
   * @static
   * @param {string} id The ActiveX id to be added to initialize the XHR object.
   * @return void
   
submit()
   * @description Method for initiating an asynchronous request via the XHR object.
   * @method asyncRequest
   * @public
   * @static
   * @param {object} request object : {	type 			: {string}, get of post
										url 			: {string} url
										scope			: {string}[optioneel]
										data			: {string}postdata url-encoded
										onsuccess 		: {object} callback
										onfailure 		: {object} callback}
   
   
setReadyStateCheckinterval()
   * @description sets interval in wich the readystate property is checked.
   * @method setReadyStateCheckinterval
   * @public
   * @static
   * @param {integer} interval value.
   * @return void
		
addPoll(poll):
   * @description adds a request-object to the polling-list,
   * requests are submitted with interval iPollingInterval   
   * @method addPoll
   * @public
   * @static
   * @param {boolean} if true than polling start on calling the function.
   * @return void 
   
clearPoll:
   * @description clears the polling list ,
   * @method clearPoll
   * @public
   * @static
   * @param 
   * @return void 
   
sendPoll(oRequest):
   * @description submits the polling-objects to the server by ,
   * passing them one by one to submit()  
   * @method sendPoll
   * @public
   * @static
   * @param {object} request object.
   * @return void 
		
startPolling:
   * @description starts the polling sequence ,
   * @method startPolling
   * @public
   * @static
   * @param 
   * @return void  

stopPolling:
   * @description stops the polling sequence ,
   * @method stopPolling
   * @public
   * @static
   * @param 
   * @return void  

setPollingInterval(interval):
   * @description sets interval in which the polling requests are made ,
   * @method setPollingInterval
   * @public
   * @static
   * @param {integer}  pollinginterval
   * @return void   


	*/
//=================================================================================================
//PRIVATE STATIC VARS EN METHODS

	var _msxml_progid=[
		"MSXML2.XMLHttp.6.0", 
		"MSXML2.XMLHttp.3.0",
	    "MSXML2.XMLHttp",
	    "Microsoft.XMLHTTP"
        ],
		_http_header={},
		_has_http_headers=false,
		_use_default_post_header=true,
		_default_post_header='application/x-www-form-urlencoded',
		_isFormSubmit=false,
		_isFileUpload=false,
		_is_polling=false,
		_formNode=null,
		_sFormData=null,
		_oFrmElements=[],
		_poll={},
		_timeOut={},
		_readystateCheck_interval=50,
		_transaction_id=0,
		_hasSubmit=false,
		_oPolling=[],//pollingobjecten
		_oXHR={};//kopie van actief xhr-object
	
	var releaseObject=function(o){
		//dereference the XHR instance.
		o.conn = null;
		//dereference the connection object.
		o = null;
	};
	
	var createXhrObject=function(transactionId){//lazy loading
			var obj,http,xhr;
			
            if (typeof XMLHttpRequest != "undefined"){
                var createXHRObject = function(transactionId){
                    http = new XMLHttpRequest();
                    obj = { conn:http, tId:transactionId };
                    return obj;
                };
            } else if (typeof ActiveXObject != "undefined"){
                var createXHRObject = function(transactionId){                    
                    if (typeof arguments.callee.activeXString != "string"){
                        var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                                        "MSXML2.XMLHttp"];
                
                        for (var i=0,len=versions.length; i < len; i++){
                            try {
                                xhr = new ActiveXObject(versions[i]);
                                arguments.callee.activeXString = versions[i];
                    			obj = { conn:xhr, tId:transactionId };
                    			return obj;
                            } 
                            catch (ex){}
                        }
                    }
                    xhr = new ActiveXObject(arguments.callee.activeXString);
                	obj = { conn:xhr, tId:transactionId };
                    return obj;
                };
            } else {
               var createXHRObject = function(transactionId){
                    throw new Error("No XHR object available.");
                };
            }
            
            
			return createXHRObject(transactionId);
        };
          
	var getConnectionObject=function(){
		var o,
			tId = _transaction_id;

		try
		{
			o = createXhrObject(tId);
			if(o){
				_transaction_id++;
			}
		}
		catch(e){}
		finally
		{
			return o;
		}
	};

	var handleReadyState=function(o, oRequest){

		if(oRequest && oRequest.timeout){
			_timeOut[o.tId] = window.setTimeout(function(){ obj.abort(o, oRequest, true); }, oRequest.timeout);
		}

		_poll[o.tId] = window.setInterval(
			function(){
				if(o.conn && o.conn.readyState == 4){
					window.clearInterval(_poll[o.tId]);
					delete _poll[o.tId];

					if(oRequest && oRequest.timeout){
						delete _timeOut[o.tId];
					}
					handleTransactionResponse(o, oRequest);
				}
			}
		,_readystateCheck_interval);
    };

    var handleTransactionResponse=function(o, oRequest, isAbort){
		// If no valid oRequest is provided, then do not process any oRequest handling.
		if(!oRequest){
			releaseObject(o);
			return;
		}

		var httpStatus, responseObject;

		try
		{
			if(o.conn.status !== undefined && o.conn.status != 0){
				httpStatus = o.conn.status;
			}
			else{
				httpStatus = 13030;
			}
		}
		catch(e){
			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
			// when the o object's status and statusText properties are
			// unavailable, and a query attempt throws an exception.
			httpStatus = 13030;
		}

		if(httpStatus >= 200 && httpStatus < 300){
			try
			{
				responseObject = createResponseObject(o, oRequest.argument);
				if(oRequest.onsuccess){
					responseObject.data=responseObject.responseText;
					if(!oRequest.scope){
						oRequest.onsuccess(responseObject);
					}
					else{
						// If a scope property is defined, the oRequest will be fired from
						// the context of the object.
						oRequest.onsuccess.apply(oRequest.scope, [responseObject]);
					}
				}
			}
			catch(e){}
		}
		else{
			try
			{
				switch(httpStatus){
					// The following cases are wininet.dll error codes that may be encountered.
					case 12002: // Server timeout
					case 12029: // 12029 to 12031 correspond to dropped connections.
					case 12030:
					case 12031:
					case 12152: // Connection closed by server.
					case 13030: // See above comments for variable status.
						responseObject = createExceptionObject(o.tId, oRequest.argument, (isAbort?isAbort:false));
						if(oRequest.onfailure){
							responseObject.data=statusText;
							if(!oRequest.scope){
								oRequest.onfailure(responseObject);
							}
							else{
								oRequest.onfailure.apply(oRequest.scope, [responseObject]);
							}
						}
						break;
					default:
						responseObject = createResponseObject(o, oRequest.argument);
						responseObject.data=statusText;
						if(oRequest.onfailure){
							if(!oRequest.scope){
								oRequest.onfailure(responseObject);
							}
							else{
								oRequest.onfailure.apply(oRequest.scope, [responseObject]);
							}
						}
				}
			}
			catch(e){}
		}

		releaseObject(o);
		responseObject = null;
    };

    var createResponseObject=function(o, oRequestArg){
		var obj = {},
			headerObj = {};

		try
		{
			var headerStr = o.conn.getAllResponseHeaders();
			var header = headerStr.split('\n');
			for(var i=0; i<header.length; i++){
				var delimitPos = header[i].indexOf(':');
				if(delimitPos != -1){
					headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
				}
			}
		}
		catch(e){}

		obj.tId = o.tId;
		obj.status = o.conn.status;
		obj.statusText = o.conn.statusText;
		obj.getResponseHeader = headerObj;
		obj.getAllResponseHeaders = headerStr;
		obj.responseText = o.conn.responseText;
		obj.responseXML = o.conn.responseXML;

		if(typeof oRequestArg !== undefined){
			obj.argument = oRequestArg;
		}

		return obj;
    };

    var createExceptionObject=function(tId, oRequestArg, isAbort){
		var COMM_CODE = 0,
			COMM_ERROR = 'communication failure',
			ABORT_CODE = -1,
			ABORT_ERROR = 'transaction obj.aborted';

		var obj = {};

		obj.tId = tId;
		if(isAbort){
			obj.status = ABORT_CODE;
			obj.statusText = ABORT_ERROR;
			obj.data = ABORT_ERROR;
		}
		else{
			obj.status = COMM_CODE;
			obj.statusText = COMM_ERROR;
			obj.data = COMM_ERROR;
		}

		if(oRequestArg){
			obj.argument = oRequestArg;
		}

		return obj;
    };
	
	var setHeader=function(o){
		for(var prop in _http_header){
			if(_http_header.hasOwnProperty(prop)){
				o.conn.setRequestHeader(prop, _http_header[prop]);
			}
		}
		delete _http_header;

		_http_header = {};
		_has_http_headers = false;
	};
	
	var resetFormstate=function(){
		_isFormSubmit = false;
		_isFileUpload = false;
		_formNode = null;
		_sFormData = "";
	};
	
	var getFormElement=function(field,query){
		
		var disabled = field.disabled,
			name = field.name,
			value = field.value;
				
		if(!disabled && name){
			switch (field.type)
			{
				case 'select-one':
				case 'select-multiple':
					if(query && name !=query){
						break;
					}
					else{
						for(var j=0; j<field.options.length; j++){
							
							var options=field.options[j];
							
							if(options.selected){
								if(window.ActiveXObject){
									_sFormData += encodeURIComponent(name) + '=' + encodeURIComponent(options.attributes['value'].specified?options.value:options.text) + '&';
								}
								else{
									_sFormData += encodeURIComponent(name) + '=' + encodeURIComponent(options.hasAttribute('value')?options.value:options.text) + '&';
								}
	
							}
						}
					}
				break;
				case 'radio':
				case 'checkbox':
					if(query && name !=query){
						break;
					}
					else if(field.checked){
						 _sFormData += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
					}
				break;
				case 'file':
					
				case undefined:
				case 'reset':
				case 'button':
				break;
				case 'submit':
					if(query && name !=query){
						break;
					}
					else if(_hasSubmit == false){
						_sFormData += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
						_hasSubmit = true;
					}
				break;
				default:
					if(query && name !=query){
						break;
					}
					else {
						_sFormData += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
					}
				break;
			}
		}	
		return _sFormData;
	};
	
	var goPolling = function(){

			var pollingTimer = setTimeout(function () {
				if(_is_polling){
					RequestManager.sendPoll(true);
				}
			}, obj.pollingInterval);
			
	};

	//PUBLIC INTERFACE ---------------------------------------------
	var obj = {

		pollingInterval : 4000,//default polling interval
		
		setProgId : function(id){
			_msxml_progid.unshift(id);
		},

		setDefaultPostHeader : function(b){
			_use_default_post_header = b;
		},

		setReadystateCheck_interval : function(i){
			if(typeof i == 'number' && isFinite(i)){
				_readystateCheck_interval = i;
			}
		},

		
		submit : function(oRequest){
		
			//oRequest.type, oRequest.url, oRequest, oRequest.data
			var o = getConnectionObject();

			if(!o){
				return null;
			}
			else{
				if(_isFormSubmit){
					if(_isFileUpload){
						uploadFile(o.tId, oRequest, oRequest.url, oRequest.data);
						releaseObject(o);

						return;
					}
					if(oRequest.type == 'get' || oRequest.type == 'GET'){
						if(_sFormData.length != 0){
							oRequest.url += ((oRequest.url.indexOf('?') == -1)?'?':'&') + _sFormData;
						}
						else{
							oRequest.url += "?" + _sFormData;
						}
					}
					else if(oRequest.type == 'post' || oRequest.type == 'POST'){
						oRequest.data = oRequest.data?_sFormData + "&" + oRequest.data:_sFormData;
					}
				}

				o.conn.open(oRequest.type, oRequest.url, true);

				if(_isFormSubmit || (oRequest.data && _use_default_post_header)){
					obj.initHeader('Content-Type', _default_post_header);
					if(_isFormSubmit){
						resetFormstate();
					}
				}

				if(_has_http_headers){
					setHeader(o);
				}
				handleReadyState(o, oRequest);
				_oXHR=o;//kopie huidig xhr-object opslaan
				o.conn.send(oRequest.data || null);
				
				return o;
			}
		},
		
		addPoll : function(oRequest){
		
			_oPolling.push(oRequest);
		},
		
		clearPoll : function(oRequest){
		
			_oPolling=[];
			this.stopPolling();
			
		},
		
		sendPoll : function(bPoll){
		
			for(var i=0;i<_oPolling.length;i++){
				var obj=_oPolling[i];
                if (obj != null) {
					this.submit(obj);
                }	
			}
			if(bPoll){
				goPolling();
			}
		},
		
		startPolling : function(){
			_is_polling=true;
			goPolling();
		},
		
		stopPolling : function(){
			_is_polling=false;
		},
		
		setPollingInterval : function(interval){
		
			if(typeof(interval) !== undefined && interval != ''){
				if(parseInt(interval)>100){
					obj.pollingInterval=parseInt(interval);
				}
			}
		},
	   
		initHeader : function(label,value){
			if(_http_header[label] === undefined){
				_http_header[label] = value;
			}
			else{
				_http_header[label] =  value + "," + _http_header[label];
			}

			_has_http_headers = true;
		},

		getForm : function(formId,query){
			resetFormstate();
			var oForm=this.getRefForm(formId),
				field;
			
			_hasSubmit = false;
			
			for (var i=0; i<oForm.elements.length; i++){
				
				field = oForm.elements[i];
				getFormElement(field,query);
			}
			_isFormSubmit = true;
			_sFormData = _sFormData.substr(0, _sFormData.length - 1);
			
			return _sFormData;
			
		},
		
		getRefForm : function(FormId){
			var obj;
			if(typeof FormId == 'undefined'){
				FormId=0;
			}
			if(typeof FormId == 'string'){
				obj = (document.getElementById(FormId) || document.forms[FormId]);
				return obj;
			}
			else if(typeof FormId == 'object'){
				obj = FormId;
				return obj;
			} 
			else if(typeof FormId == 'number'){
				obj = document.forms[FormId];
				return obj;
			}
			else{
				return false;
			}
		},
		
		getFormElements : function(formId){
			//to do : filteren met een allowed-array
			var oForm = this.getRefForm(formId),
				field, name, disabled, oFrmElements;

			for (var i=0; i<oForm.elements.length; i++){
				field = oForm.elements[i];
				disabled = field.disabled;
				name = field.name;
				if(!disabled && name){
					_oFrmElements[name]=field;
				}
				
			}
			return _oFrmElements;
		},
		
		setField : function(name,value,oForm){
				var frmElements=this.getRefForm(oForm),
					obj=frmElements[name];
				typeof(value)=='undefined'?value=false:void(0);//radio en checkboxes
				
				try
				{
					switch(obj.type)
					{
							case 'text' 			:
							case 'hidden' 			:	
							case 'select-one' 		:
							case 'select-multiple' 	:
								obj.value=value;
								//to do : multiple selectboxes
							break;					
							case 'textarea' 		:
								obj.value=value;
							break;
							case 'checkbox'			:
							case 'radio'			:// 1 radiobutton
								(value=='false'||value=='')?value=false:value=true;
								obj.checked=value;
							break;
							case undefined			://radiogroup
							
								for(var i=0;i<obj.length;i++){
									var el=obj[i];
									value==el.value ? el.checked=true : el.checked=false;
								}
							break;
							default 				:
								alert('No catch ' + typeof(obj));
							break;
					}
				} 
				catch(e){ return false;}
				
				return true;
			},

		abort : function(o, oRequest, isTimeout){
			if(obj.isCallInProgress(o)){
				o.conn.obj.abort();
				window.clearInterval(_poll[o.tId]);
				delete _poll[o.tId];
				if(isTimeout){
					delete _timeOut[o.tId];
				}

				handleTransactionResponse(o, oRequest, true);

				return true;
			}
			else{
				return false;
			}
		},

		isCallInProgress : function(o){
			// if the XHR object assigned to the transaction has not been dereferenced,
			// then check its readyState status.  Otherwise, return false.
			
			if(typeof(o)=='undefinded'){
				o=_oXHR;
			}
			if(o.conn){
				return o.conn.readyState != 4 && o.conn.readyState != 0;
			}
			else{
				//The XHR object has been destroyed.
				return false;
			}
		}
		
	}
	return obj;
	
})();

