// ajax.js - shared code for implementing AJAX functionalities
//
// Note: Set handleServerResponse to a customized fcn to handle the received XML data.
//
// V1.0 - 2007-11-02
// V1.1 - allow handling of error in xmlHttp responses

AJAX_TIMEOUT = 10000;	// Time to wait for an AJAX response before timeout, in ms

// holds an instance of XMLHttpRequest
var xmlHttp = createXmlHttpRequestObject();

// holds the last error msg
var xmlHttpError = "";

// function to async handle server response and error
var handleServerResponse = function _defaultHandleServerResponse() {};
var handleXMLHttpError = function _defaultHandleXMLHttpError() {};	// V1.1

function _defaultTimeoutHandler()   // Default timeout handler
{
  xmlHttp.abort();
  xmlHttpError = "Timeout waiting for response.";
  clearTimeout(requestTimer);
}   /* _defaultTimeoutHandler */

// function to handle request timeout
var timeoutHandler = _defaultTimeoutHandler;
var requestTimer;

// function to submit given HTML form to dest script via AJAX
function ajaxSubmitForm(form, dest)
{
  var params = "";
  for (var i = 0; i < form.elements.length; i++) {
    if (form.elements[i].type == "radio" && !form.elements[i].checked) continue;   // skip unchecked radio but
    str = new String( form.elements[i].value );
    str = str.replace(/&/g, '%26');    // special handling of & etc...
    str = str.replace(/%/g, '%25');
    str = str.replace(/\+/g, '%2B');
    params += form.elements[i].name + "=" + str + "&";
  }
  loadScriptAsync(dest, params);
}   /* ajaxSubmitForm */

// Check given XML structure.  Returns "" if ok or error msg
function checkXmlStructure(xmlResponse)
{
  // catching potential errors with IE and Opera
  if (!xmlResponse || !xmlResponse.documentElement) {
//    cleanup('Ƶc~AЦAաC', true);
    return ("Invalid XML structure:\n" + xmlHttp.responseText);
  }
  // catching potential errors with Firefox
  var rootNodeName = xmlResponse.documentElement.nodeName;
  if (rootNodeName == "parsererror") {
//    cleanup('Ƶco{~AЦAաC', true);
    return ("Invalid XML structure");
  }
  return "";
}   /* checkXmlStructure */

// creates an XMLHttpRequest instance
function createXmlHttpRequestObject() 
{
  xmlHttpError = "";
  // will store the reference to the XMLHttpRequest object
  var xmlHttp;
  // this should work for all browsers except IE6 and older
  try {
    // try to create XMLHttpRequest object
    xmlHttp = new XMLHttpRequest();
  } catch(e) {
    // assume IE6 or older
    var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0",
                                    "MSXML2.XMLHTTP.5.0",
                                    "MSXML2.XMLHTTP.4.0",
                                    "MSXML2.XMLHTTP.3.0",
                                    "MSXML2.XMLHTTP",
                                    "Microsoft.XMLHTTP");
    // try every prog id until one works
 
    for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++) {
      try {  // try to create XMLHttpRequest object
        xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
      } 
      catch (e) {}
    }
  }
  // return the created object or set an error message
  if (!xmlHttp) {
    xmlHttpError = "Error creating the XMLHttpRequest object.";
  }

  return xmlHttp;
}   /* createXmlHttpRequestObject */

// Return the (n)th child of given element identified by given tag name
function getChild(element, tagname, n)
{
  try {
    child = element.getElementsByTagName(tagname).item(n).firstChild;
  } catch(e) {
    child = null;
  }
  return child;
}   /* getChild */

// Return value of the (n)th child of the element with given tag name, or defaultValue if not found
function getChildValue(element, tagname, n, defaultValue)
{
  child = getChild(element, tagname, n);
  if (child)
    return child.data;
  else
    return defaultValue;
}   /* getChildValue */

// function called when the state of the HTTP request changes
function handleRequestStateChange()
{
  // when readyState is 4, we are ready to read the server response
  if (xmlHttp.readyState == 4) {
    xmlHttpError = "";
    clearTimeout(requestTimer);
    // continue only if HTTP status is "OK"
    if (xmlHttp.status == 200) {
      try {
        // do something with the response from the server
        handleServerResponse();
      } catch(e) {
        // set error message
        xmlHttpError = "Error reading the response: " + e.toString();
      }
    } else {
      // set status message
      xmlHttpError = "There was a problem retrieving the data: " + xmlHttp.statusText;
      handleXMLHttpError();
    }
  } else {
    if (xmlHttpError != "") {   // display and reset any error msg
      alert(xmlHttpError);
      xmlHttpError = "";
    }
  }
}   /* handleRequestStateChange */

// function to submit given params to dest script via AJAX
function loadScriptAsync(dest, params)
{
  if (xmlHttp) {
    try  {  // submit to given program
      xmlHttpError = "";
      requestTimer = setTimeout(timeoutHandler, AJAX_TIMEOUT);

      xmlHttp.open("POST", dest, true);
      xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xmlHttp.onreadystatechange = handleRequestStateChange;
      xmlHttp.send(params);
    } catch (e) {
      // display an error when failing to connect to the server
      xmlHttpError = e.toString();
    }
  }
}	/* loadScriptAsync */

// end of script
