 // ------------------------------------------
 //  Basic AJAX functionality © Mikko Junnila
 //
 //    08.03.2008 / mikko.junnila@gmail.com
 // ------------------------------------------


 // top-level functions
 function ajaxGET(id, url, callback, timeout) { setTimeout(function() { xmlRequest(id, url, callback, "GET"); }, timeout); }
 function ajaxPOST(id, url, callback, timeout) { setTimeout(function() { xmlRequest(id, url, callback, "POST"); }, timeout); }

 function handle_response(xmlobj)
 {
   var success = true;
   // invoke the callback function with appropriate parameters
   xmlobj.callback(success, xmlobj.id, xmlobj.xmlhttp.responseText);
 }

 function handle_error(xmlobj)
 {
   var success = false;
   // invoke callback with an error message
   xmlobj.callback(success, xmlobj.id, "error");
 }


 // ######################################################################################################

 // global array for xmlHttp requests
 var xmlreqs = new Array();

 // --------------------------------------------------------------------------------------------------------------

 // class for holding the object
 function XMLObj(id, freed, callback)
 {
   // the id is used so that the correct block on the page can be updated
   this.id = id;

   // 'freed' tracks if xmlreq-object is free to use
   this.freed = freed;

   // callback function which should be called when page fully loaded
   this.callback = callback;

   // reset the xmlhttp variable
   this.xmlhttp = false;

   // create the xmlhttp request
   if (window.ActiveXObject) { this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
   else if (window.XMLHttpRequest) { this.xmlhttp = new XMLHttpRequest(); }
   else { handle_error(id, "couldn't create a xmlHttp object."); }
 }

 // --------------------------------------------------------------------------------------------------------------

 // called when the state of a xmlhttp-connection changes
 function xmlhttpChange(pos)
 {
   // make sure the http state is 4 (transfer complete) and that no error has occurred
   if (typeof(xmlreqs[pos]) != 'undefined' && xmlreqs[pos].freed == 0 && xmlreqs[pos].xmlhttp.readyState == 4)
   {
     if (xmlreqs[pos].xmlhttp.status == 200 || xmlreqs[pos].xmlhttp.status == 304)
     {
       // everything seems ok, let's handle the html response
       handle_response(xmlreqs[pos]);
     }
     else
     {
       // handle the error to a specific block
       handle_error(xmlreqs[pos]);
     }

     // free the object so it can be reused
     xmlreqs[pos].freed = 1;
   }
 }

 // --------------------------------------------------------------------------------------------------------------

 function xmlRequest(id, url, callback, type)
 {
   var pos = -1;

   // try to find a free object
   for (var i = 0; i < xmlreqs.length; i++)
   {
     // if a free object is found, update the position and the id of that object
     if (xmlreqs[i].freed == 1)
     {
       pos = i;
       xmlreqs[pos].id = id;
       xmlreqs[pos].callback = callback;
       break;
     }
   }

   // if a free object was not found, set the position to the
   // end of the xmlHttp array and create a new object there
   if (pos == -1)
   {
     pos = xmlreqs.length;
     xmlreqs[pos] = new XMLObj(id, 1, callback);
   }

   // make sure a xmlHttp object was succesfully created
   if (xmlreqs[pos].xmlhttp)
   {
     // reserve the object for us so others can't use it
     xmlreqs[pos].freed = 0;

     // open connection for the given url
     xmlreqs[pos].xmlhttp.open(type, url, true);

     // specify what to do when connection state changes
     xmlreqs[pos].xmlhttp.onreadystatechange = function() { xmlhttpChange(pos); }

     // send the request based on the browser
     if (window.XMLHttpRequest) { xmlreqs[pos].xmlhttp.send(null); }
     else if (window.ActiveXObject) { xmlreqs[pos].xmlhttp.send(); }
   }
 }

