var xmlHttpReq;
var onAjaxResponse;
var onBeforeAjaxPostback;

// "Replacement" function used by AjaxDisabler & AjaxPanel with RefreshOnly option
if (typeof(__doPostBack) == 'function')
	__doAPostBack=__doPostBack;

function FunctionQueueManager(queueCapacity)
{
	var m_Capacity = (queueCapacity)? queueCapacity: Infinity;
	var self = this;
	var m_Requests;
	var m_Count;
	var m_Busy;
	
	function Init()
	{
		m_Requests = new Array();
		m_Count = 0;
		m_Busy = false;
	}
	
	Init();

	this.Enqueue = function()
	{
		if (m_Count < m_Capacity)
		{
			m_Requests.push(new QueueManagerRequest(arguments));
			m_Count++;
		}
		
		ExecuteNext();
	}
	
	function ExecuteNext()
	{
		if (m_Busy)
			return;
	
		var nextRequest = GetPeek();
		
		if (nextRequest == null)
			return;
			
		m_Busy = true;
		
		nextRequest.Execute();
	}
	
	this.Dequeue = function()
	{
		if (m_Count == 0)
			return;
			
		m_Requests.shift();
		m_Count--;
		
		m_Busy = false;
		
		ExecuteNext();
	}
	
	this.Clear = function()
	{
		Init();
	}

	function GetPeek()
	{
		if (m_Count == 0)
			return null;
			
		return m_Requests[0];
	}
	
	function QueueManagerRequest(args)
	{
		var m_Func = args[0];
		var m_Args = ConvertArgsToArray(args);
		
		this.Execute = function()
		{
			m_Func.apply(this, m_Args);
		}
		
		function ConvertArgsToArray(argsToConvert)
		{
			var result=new Array();
		
			for(var i=1; i<argsToConvert.length; i++)
				result.push(argsToConvert[i]);
			
			return result;
		}
	}
}

// encapsulate a request and its event target + argument
function BvdXmlHttpRequest(xmlHttpRequest, eventTarget, eventArgument)
{
  this.request=xmlHttpRequest;
  this.requestEventTarget=eventTarget;
  this.requestEventArgument=eventArgument;
}

function CreateXMLHTTP()
{
     var retval=null;
     try
     {
          retval=new ActiveXObject("Msxml2.XMLHTTP");
     }
     catch(e)
     {
          try
          {
               retval=new ActiveXObject("Microsoft.XMLHTTP");
          } 
          catch(oc)
          {
               retval=null;
          }
     }

     if(!retval && typeof XMLHttpRequest != "undefined") 
     {
          retval=new XMLHttpRequest();
          if (retval.overrideMimeType) 
            retval.overrideMimeType('text/xml'); 
     }

     return retval;
}


function ajaxCallBack(xmlHttpReq, callBackFunction)
{
	if( xmlHttpReq && xmlHttpReq.request )
	{
		// See if ajax callback mechanism is finished
		if( xmlHttpReq.request.readyState==4 )
		{
			// Only treat the response if no error occured
			if( xmlHttpReq.request.status==200 )
			{
				parseAjaxResponse(function()
				    {
				        var ret = AjaxResponse();
				        ret.request = xmlHttpReq;
				        ret.content = xmlHttpReq.request.responseText;
				        ret.callBackFunction = callBackFunction;
				        return ret;
				     }());
			}
			return ;
		}
	}
}

function AjaxResponse()
{
    var ret={};
    ret.request = null;
    ret.content = null;
    ret.callBackFunction = null;
    ret.controls = null;
    ret.controlIndex = null;
    ret.foundCtrl = null;
    return ret;
}

function parseAjaxResponse(params)
{
    /*
	ResponseText of xmlHttpRequest is formatted as
	$$-$$clientid1$$-$$content1$$-$$
	$$-$$clientid2$$-$$content2$$-$$
	$$-$$clientid3$$-$$content3$$-$$
	(without end-of-line)
	*/
	if(params.content != null)
	{
	    params.controls = params.content.split ("$$-$$");
	    params.controlsIndex = 0;
	    params.foundCtrl = false;

	    LoadControls(params);
	}
}

function LoadControls (params)
{
	/*
	Replace each content (linked to the document by its clientid)
	If no content has been replaced, something is not working correctly.
	In that case, do a classic submit
	*/
	var n = params.controls.length - 2; // as controlsIndex is increased by 3
	while (params.controlsIndex < n)
	{
		var responseType = params.controls[params.controlsIndex++];
		var id = params.controls[params.controlsIndex++];
		var content = params.controls[params.controlsIndex++];

		//1 = StartupScript, 2 = ClientScript, 3 = InlineScript
		if (responseType == "1" || responseType == "2" || responseType == "3")
		{
			JSProfile(content);
			try
			{
				if(window.execScript)
					window.execScript(content,"javascript");
				else
					window.setTimeout(content,0);
			}
			catch(e)
			{
				if (JsDebug)
				{
					alert("Javascript error during ajax refresh: " + e.name + " - " + e.message); 
					alert(content);
				}
			}
			JSProfile(content);
			continue;
		}

		//4 = HiddenField
		if (responseType == "4")
		{
			elem = document.forms[0][id];
			if (elem != null) //The input field already exists
			{
				if (elem.type == "hidden") //we only consider the hidden field (for the moment)
				{
					elem.value = content;
				}
			}
			else
			{
				var inputHiddenField = document.createElement("INPUT");
				inputHiddenField.type = "hidden";
				inputHiddenField.id = id; 
				inputHiddenField.name = id; 
				inputHiddenField.value = content; 

				document.forms[0].appendChild(inputHiddenField);
			}

			continue;
		}

		//5 = AjaxPanel
		if (responseType == "5")
		{
			var elem = document.getElementById (id);
			if (elem != null)
			{
				params.foundCtrl = true;
				elem.innerHTML = content; 
				continue;
			}
		} 

		//6 = Array
		if (responseType == "6")
		{
			try
			{
				if( window.execScript )
					window.execScript(id + '=' + content,"javascript");
				else
					window.setTimeout(id + '=' + content,0);
			}
			catch(e)
			{}
		}

		//7 = Transfer
		if (responseType == "7")
		{
			document.location = content;
		}
		
		//8 = JsSource
		if (responseType == "8")
		{
			var scriptArray = document.getElementsByTagName("Script");
			var found = false;
			for(var i=0; i<scriptArray.length;i++)
			{
				if(scriptArray[i].getAttribute("src") == content)
				{
					found = true;
					break;
				}
			}
			if(!found)
			{
				var script = document.createElement("script");
				script.src = content;
				script.type = "text/javascript";
				var cbFunction = function()
					{
						LoadControls (params);
					}
				script.onload = cbFunction;
				script.onreadystatechange = function() 
					{
						if (this.readyState == 'complete' || this.readyState == 'loaded') 
						{
							cbFunction ();
						}
					}
				document.body.appendChild(script);
				if (!script.complete)
					return;
			}
		}
	}

	if( !params.foundCtrl )
	{
		// Restore cursor
		document.body.style.cursor = "auto";

		/*
		Something went wrong and response does not match request.
		So redo the postback using classic way
		*/
		if (params.xmlHttpReq != null && params.xmlHttpReq.requestEventTarget != null)
		{
		    if (typeof(__doPostBack) != "undefined")
			    return __doPostBack(params.xmlHttpReq.requestEventTarget, params.xmlHttpReq.requestEventArgument);
			else
			    document.forms[0].submit ();
		}
	}
	else
	{
		/*
		Ajax mechanism is now finished.
		Let inform the user of this ajaxPostBack do whatever he
		judges important when every content has been updated
		(like resizing window, ...)
		*/
		if( onAjaxResponse != undefined )
			onAjaxResponse ();
			
		if (params.callBackFunction != null)
			params.callBackFunction ();
	}
	// Restore cursor
	document.body.style.cursor = "auto";
	
	m_AjaxPanelPostBackManager.Dequeue();
}

function ajaxPostBack(eventTarget, eventArgument)
{
	ajaxPanelPostBack(null, eventTarget, eventArgument);
}

function ajaxPanelPostBack(ajaxGroupId, eventTarget, eventArgument) 
{
    if (onBeforeAjaxPostback != undefined)
        onBeforeAjaxPostback();

	m_AjaxPanelPostBackManager.Enqueue(ExecuteAjaxPanelPostBack, ajaxGroupId, eventTarget, eventArgument);
}

function ExecuteAjaxPanelPostBack(ajaxGroupId, eventTarget, eventArgument)
{	
	if (BvdPageDisplayProgressCursor)
		document.body.style.cursor = "wait";
	BvdPageDisplayProgressCursor = true;
	
	if (typeof(document.forms[0].__EVENTTARGET) != "undefined")
	{
	    document.forms[0].__EVENTTARGET.value=eventTarget.split("$").join(":");  
	    document.forms[0].__EVENTARGUMENT.value=eventArgument;
	}

	var url=document.forms[0].action;
	var urlParameters="";
	/*
	Constructs url parameters from the document =
	all inputs
	+
	textareas
	*/
	var inputs=document.getElementsByTagName("input");
	for(var idxInput=0; idxInput<inputs.length; ++idxInput)
	{
		var name=inputs[idxInput].name;
		var type = inputs[idxInput].type;
		if ((type == "hidden") ||(type == "text") || (((type == "checkbox") || (type == "radio")) && (inputs[idxInput].checked)))
		{
			var value = encodeURIComponent(inputs[idxInput].value);
			urlParameters=urlParameters+name+"="+value;
			urlParameters=urlParameters+"&";
		}
	}
		
	var textareas=document.getElementsByTagName("textarea");
	for(var idxTextArea=0; idxTextArea<textareas.length; ++idxTextArea)
	{
		urlParameters=urlParameters+textareas[idxTextArea].name+"="+encodeURIComponent(textareas[idxTextArea].value);
		urlParameters=urlParameters+"&";
	}

	var selects=document.getElementsByTagName("select");
	for(var idxSelect=0; idxSelect<selects.length; ++idxSelect)
	{
		urlParameters=urlParameters+selects[idxSelect].name+"="+encodeURIComponent(selects[idxSelect].value);
		urlParameters=urlParameters+"&";
	}
		
	/*
	Indicates it is an ajaxPostBack for the server to format the response
	accordingly
	*/
	urlParameters=urlParameters+"ajaxids="+eventTarget;
	if (ajaxGroupId != null && ajaxGroupId.length > 0)
			urlParameters=urlParameters+"&ajaxgroupid="+ajaxGroupId;

	var xmlHttpReq=new BvdXmlHttpRequest(CreateXMLHTTP(), eventTarget, eventArgument);
	xmlHttpReq.request.open('POST', url, true);
		
	xmlHttpReq.request.onreadystatechange = function () { ajaxCallBack(xmlHttpReq, null);};
	xmlHttpReq.request.setRequestHeader("Content-Transfer-Encoding", "quoted-printable");
	xmlHttpReq.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	xmlHttpReq.request.setRequestHeader("Content-length", urlParameters.length);

	xmlHttpReq.request.send(urlParameters);
	if (typeof(document.forms[0].__EVENTTARGET) != "undefined")
	{
	    document.forms[0].__EVENTTARGET.value = "";  
	    document.forms[0].__EVENTARGUMENT.value = "";
	}
}

// UrlParamaters 
// Call Back function is used to be notified of the completion of this ajax request
// The doGetRequest is used when we want to use the browser caching mechanism
function ajaxRequest(url, urlParameters, callBackFunction, doGetRequest, skipCache) 
{
	if (typeof(doGetRequest) == "undefined") doGetRequest = false;
	if (typeof(skipCache) == "undefined") skipCache = false;
	/* 
	Indicates this is an ajaxRequest for the server to format the response
	accordingly
	*/
	if(doGetRequest)
	{
		url +="&AjaxRequest=1";
		if (skipCache)
		{
			url += "&ts=" + new Date().getTime();
		}
	}
	else
		urlParameters += "&AjaxRequest=1";
	var xmlHttpReq=new BvdXmlHttpRequest(CreateXMLHTTP());
	
	if (BvdPageDisplayProgressCursor)
		document.body.style.cursor = "wait";
	BvdPageDisplayProgressCursor = true;
		
	xmlHttpReq.request.open(doGetRequest?"GET":"POST", url, true);
  
	xmlHttpReq.request.onreadystatechange = function () { ajaxCallBack(xmlHttpReq, callBackFunction);};
	xmlHttpReq.request.setRequestHeader("Content-Transfer-Encoding", "quoted-printable");
	xmlHttpReq.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	if (!doGetRequest)
		xmlHttpReq.request.setRequestHeader("Content-length", urlParameters.length); 
	xmlHttpReq.request.send(urlParameters);
}

m_AjaxPanelPostBackManager = new FunctionQueueManager(5);
