// a set of functions for working with the site scripts through
// AJAX technology

// the time (in milliseconds) between requests
var normalRequestDelay = 20;

// the maximal number of the same URL requests,
// which could be procceeded, when their count will
// exceed this value, they will beskept until the other
// URL will be treated
// also the requestDelay will be a multiplication to a power 2
// of this value to normalRequestDelay: sometimes it helps
// the request to run
// the count will be resetted every previousUrlCountPeriod milliseconds
var maxSameUrlRequestsSequence = 10;
var previousUrlCountPeriod = 5000;
var previousUrl = "";
var previousUrlCount = 0;
setInterval( function() 
  {
    previousUrl = "";
    previousUrlCount = 0;
  },
  previousUrlCountPeriod
);

// ------------------------------------------------------------------
// updates the AJAX progress bar prototype.
// Write the same function and set it's name to 
// updateAjaxProgressFunction variable
function updateAjaxProgressPrototype( currentRequestUrl ) { window.status = currentRequestUrl }
var updateAjaxProgressFunction = updateAjaxProgressPrototype;

// the XML HTTP Request object
var xmlhttp = 0;

// the requests stack
var requests = new Array();

// ------------------------------------------------------------------
// the requests sender
function sendNextRequest()
{
  setTimeout
  ( 
    function()
    {
      if ( requests.length > 0 )
      {
        // checking the URL to prevent the infinite loops
        if ( previousUrl == requests[0]['url'] )
        {
          // if exceeded
          if ( previousUrlCount >= maxSameUrlRequestsSequence )
          {
            //alert( "Зависло. :(" );
            // reomoving
            moveToNextRequest();
            // continuing proceeding
            sendNextRequest();
            return;
          };
          previousUrlCount++;
        }
        else
        {
          previousUrl = requests[0]['url'];
          previousUrlCount = 1;
        };
      
        // sending the current request
        //window.status = "sending " + requests[0]['url'];
        requests[0]['function']();
        // updating the progress
        var ui = requests[0]['url'];
        updateAjaxProgressFunction( requests[0]['url'] );
        // moving all elements
        // not using push and shift due to compatibility reasons
        moveToNextRequest();
        updateAjaxProgressFunction( ui );
      };
    }, 
    normalRequestDelay * previousUrlCount * previousUrlCount
  );
}

// ------------------------------------------------------------------
// removes the zero element from the request array and
// makes the other indicies on one lower
function moveToNextRequest()
{ 
  var tempArray = new Array();
  if ( requests.length > 1 )
    for ( var i = 0; i < requests.length - 1; i ++ )
    {
      // this is the most safe way for this operation, in IE the most required
      tempArray[i] = Array();
      tempArray[i]['url'] = requests[i+1]['url'];
      tempArray[i]['function'] = requests[i+1]['function'];
    }
  else
    tempArray = new Array();
  delete requests;
  requests = tempArray;
}

// ------------------------------------------------------------------
// adds the new request to stack from the end
function addRequestLast( request )
{ 
  // the different treatment (with sending request) is required
  // if this request will be the first in the stack
  if ( requests.length > 0 )
    requests[ requests.length ] = request;
  else
    addRequestFirst( request );
}

// ------------------------------------------------------------------
// adds the new request to stack from the beginning
function addRequestFirst( request )
{ 
  if ( requests.length > 0 )
    for ( var i = requests.length; i > 0; i-- )
      requests[i] = requests[i-1];
  requests[0] = request;
  
  // sending the request, if the XML HTTP request object is ready and
  // this is the only request, so there's no trigger for running this
  // request when the previous will be finished
  if ( requests.length == 1 && ( xmlhttp.readyState == 4 || xmlhttp.readyState == 0 ) )
    sendNextRequest();
}

// ------------------------------------------------------------------
// builds and returns the request from the URL and the function.
// the function is a fucntions without parameters, that should
// run as a request, the URL is for debug and information:
// this is an URL, which the function requests
function formRequest( url, func )
{
  var request = new Array();
  request['url'] = url;
  request['function'] = func;
  return request;
}

// ------------------------------------------------------------------
// tryes to create the XML HTTP request object
// (got from http://www.jibbering.com/2002/4/httprequest.html)
function initXmlHttp()
{
  /*@cc_on @*/
  /*@if (@_jscript_version >= 5)
  // JScript gives us Conditional compilation, we can cope with old IE versions.
  // and security blocked creation of the objects.
   try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   } catch (e) {
    try {
     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (E) {
     xmlhttp = false;
    }
   }
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest!='undefined') 
  {
  	try 
    {
  		xmlhttp = new XMLHttpRequest();
  	}
    catch (e) 
    {
  		xmlhttp=0;
  	}
  }
  if (!xmlhttp && window.createRequest) 
  {
  	try 
    {
  		xmlhttp = window.createRequest();
  	} 
    catch (e) 
    {
  		xmlhttp=0;
  	}
  };
  
  // checking, if the XML HTTP request object is ready
  //if ( xmlhttp )
    //xmlHttpBusy = false;
}

// ------------------------------------------------------------------
// adds the request to the next function
function sendUrlResponseXmlToFunction( url, callback, params, noRetry )
{
  addRequestLast( formRequest( url, function(){ sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry ) } ) );
}
// loads the output of the URL with POST params (if any), given
// and sends it as an XML object to the handler function
// Note, that the request is sent as GET, if there is no params set
// and as POST otherwise. The name of POST param are the
// params array index
function sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )
{
  // checking if the XML HTTP request object is ready
  if ( xmlhttp.readyState != 4 && xmlhttp.readyState != 0 )
  {
    // delaying the request
    if ( !noRetry )
    {
      window.status = "XMLHTTP not ready " + url;
      //addRequestFirst( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} );
      addRequestLast( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} ) );
    };
    return;
  };
  
  // now busy
  //xmlHttpBusy = true;
    
  // formatting URL to replace &amp; with &
  url = url.replace( /&amp;/g, "&" );
  
  var paramsString = "";
    
  // building the request
  if ( !params )
  {
    xmlhttp.open("GET", url, true);
  }
  else
  {
    // forming the params string
    for ( var paramName in params )
    {
      if ( paramsString != "" )
        paramsString += "&";
      paramsString += paramName + "=" + escape( params[paramName], true );
    };
    
    //Send the proper header information along with the request
    xmlhttp.open("POST", url, true);
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader("Content-length", paramsString.length);
    //xmlhttp.setRequestHeader("Connection", "close");
  };

  xmlhttp.onreadystatechange = function() 
  {
    // an exception comes here from time to time, so...
    try
    {
      // filling with the content, if any
      if ( xmlhttp.readyState == 4 )
      {
        // debug info
        //window.status = "got " + xmlhttp.status + " for " + url;
        // debug info
        if ( xmlhttp.status == 200 )
        {
          // due to gotta return the function to free the XML HTTP Request
          // object, using the timer
          if ( xmlhttp.responseXML && xmlhttp.responseXML.firstChild )
            callback( xmlhttp.responseXML );
          else
          {
            // the empty response is an error sign
            if ( xmlhttp.responseText == "" )
            {
              if ( !noRetry )
              {
                window.status = "XMLHTTP response is empty " + url;
                //addRequestFirst( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} );
                addRequestLast( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} ) );
              };
            }
            else
            {
              callback( xmlhttp.responseText );
            };
          }
          //setTimeout( function(){ callback( xmlhttp.responseXML ); }, retryDelay );
          //addRequestFirst( formRequest( url, function(){ callback( xmlhttp.responseXML ); } );
        }
        // the bad gateway message comes from time to time, so retrying
        else if ( xmlhttp.status == 502 )
        {
          window.status = "server error, resending " + url;
          addRequestLast( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} ) );
        }
      
        // now ready
        //xmlHttpBusy = false;
        // opening the next request
        sendNextRequest();
      }
    }
    catch ( e )
    { 
      // retrying
      if ( !noRetry )
      {
        window.status = "caught " + e.message + ", resending" + url;
        //addRequestFirst( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} );
        addRequestLast( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} ) );
      }
      else
      {
        window.status = "caught " + e.message + ", not resending" + url;
      };
    };
  };
  
  // sending the request
  xmlhttp.send( paramsString );
}

// ------------------------------------------------------------------
// adds the request to the next function
function sendUrlResponseTextToFunction( url, callback, params, noRetry )
{
  addRequestLast( formRequest( url, function(){ sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry ) } ) );
}
// loads the output of the URL with POST params (if any), given
// and sends it as a string to the handler function
// Note, that the request is sent as GET, if there is no params set
// and as POST otherwise. The name of POST param are the
// params array index and the value will be encoded with escape( ..., true )
// function from the corresponding array entry value
// if noRetry is true, the function will not be recalled, if the XML HTTP
// was busy
function sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )
{
  // checking if the XML HTTP request object is ready
  if ( xmlhttp.readyState != 4 && xmlhttp.readyState != 0 )
  {
    // delaying the request
    if ( !noRetry )
    {
      window.status = "XMLHTTP not ready " + url;
      //addRequestFirst( function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} );
      addRequestLast( formRequest( url, function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} ) );
    };
    return;
  };
  
  // now busy
  //xmlHttpBusy = true;
    
  // formatting URL to replace &amp; with &
  url = url.replace( /&amp;/g, "&" );
  
  var paramsString = "";
  
  // building the request
  if ( !params )
  {
    xmlhttp.open("GET", url, true);
  }
  else
  {
    // forming the params string
    for ( var paramName in params )
    {
      if ( paramsString != "" )
        paramsString += "&";
      paramsString += paramName + "=" + escape( params[paramName], true );
    };
    
    //Send the proper header information along with the request
    xmlhttp.open("POST", url, true);
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader("Content-length", paramsString.length);
    //xmlhttp.setRequestHeader("Connection", "close");
  };

  xmlhttp.onreadystatechange = function() 
  {
    try
    {
      // filling with the content, if any
      if ( xmlhttp.readyState == 4 )
      {
        // debug info
        //window.status = "got " + xmlhttp.status + " for " + url;
        // an exception comes here from time to time, so...
        if ( xmlhttp.status == 200 )
        {
          // the empty response is an error sign
          if ( xmlhttp.responseText == "" )
          {
            if (!noRetry)
            {
              //addRequestFirst( formRequest( url, function(){sendUrlResponseXmlToFunctionRequest( url, callback, params, noRetry )} );
              window.status = "XMLHTTP response is empty " + url;
              addRequestLast( formRequest( url, function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} ) );
            };
          }
          else
          {
            // due to gotta return the function to free the XML HTTP Request
            // object, using the timer
            callback( xmlhttp.responseText );
            //addRequestFirst( formRequest( url, function(){ callback( xmlhttp.responseText ); } );
          };
        }
        // the bad gateway message comes from time to time, so retrying
        else if ( xmlhttp.status == 502 )
        {
          window.status = "server error, resending " + url;
          addRequestLast( formRequest( url, function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} ) );
        }
        // now ready
        //xmlHttpBusy = false;
        // opening the next request
        sendNextRequest();
      }
    }
    catch ( e )
    { 
      // retrying
      if ( !noRetry )
      {
        window.status = "caught " + e.message + ", resending" + url;
        addRequestLast( formRequest( url, function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} ) );
      }
      else
      {
        window.status = "caught " + e.message + ", not resending" + url;
      };
        //addRequestFirst( formRequest( url, function(){sendUrlResponseTextToFunctionRequest( url, callback, params, noRetry )} );
    };
      
  };
  
  // sending the request
  xmlhttp.send( paramsString );
}

// initializing the AJAX module
initXmlHttp();

// ------------------------------------------------------------------
// returns the number of requests, left to be proceeded
function getRequestsCount()
{
  return requests.length;
}

// ------------------------------------------------------------------
// returns the the child node with name given,
// for the XML element, given, 
// returns false on error
function getNodesWithName( xmlNode, nodeName )
{
  var temp = xmlNode.childNodes;
  var output = new Array();
  var outputI = 0;
  for ( var i = 0; i < temp.length; i++ )
    if ( temp[i].tagName == nodeName )
    {
      output[outputI] = temp[i];
      outputI++;
    };

  // done
  return output;
}

