/*****************************
  Ajax wrapper class object.
  Include this script to make asynchroneous HttpRequest calls to the server
  and retrieve either a text or XML response.
******************************/
AjaxCaller = {
  debugMode : false,  //If true, debug alert messages appear throughout each call.

  xmlHttpObjects : new Array(),  //Collection of XmlHttpRequest objects used or in use.
  pendingResponseCount : 0, //Number of pending responses coming back from server.

  /***************************************
    PUBLIC METHODS
  ****************************************/

  /******************
    Execute server request using either GET request type and return either XML or text response.
    url - Full URL String pointing to server page to request.
    vars - Associative Array of GET or POST variables in format: Array[name] = value;
    callBackFunction - Function which will be called once response is complete.
  *******************/
  getXml : function(url, vars, callBackFunction) {
    this._callServer(url, vars, callBackFunction, true, "GET", null);
  },

  getText : function(url, vars, callBackFunction) {
    this._callServer(url, vars, callBackFunction, false, "GET", null);
  },

  postXml : function(url, vars, callBackFunction) {
    this._callServer(url, null, callBackFunction, true, "POST", vars);
  },

  postText : function(url, vars, callBackFunction) {
    this._callServer(url, null, callBackFunction, false, "POST", vars);
  },


  /**************************************
    PRIVATE METHODS
  ***************************************/

  /****************
    Creates XmlHttpRequest to call request on server.
    
    Parameters:
    - url : page url location to load
    - urlVars : Associative array containing array["key"]=value pairs to be appended to Url.
    - callBackFunction : Calls this function when request is complete.
    - returnXml : Boolean value indicating whether response is returned as XML or PlainText.
    - requestMethod : HTTP header type: GET, POST, etc.
    - bodyVars : Associative array containing array["key"]=value pairs used to set POST variables.
  *****************/
  _callServer : function(url, urlVars, callBackFunction, returnXml, requestMethod, bodyVars) {
    //Set up post or get variable strings
    urlVars = this._createVarsString(urlVars);
    if (urlVars.length > 0) {
      url += "?" + urlVars;
    }
    bodyVars = this._createVarsString(bodyVars);

    this._debug("_callServer() called. About to request URL\n"
        + "XmlHttpRequest Count: [" + this.xmlHttpObjects.length + "]\n"
        + "URL: [" + url + "]\n"
        + "Return XML Response: [" + returnXml + "]\n"
        + "Request Method: [" + requestMethod + "]\n"
        + "urlVars: [" + urlVars + "]\n"
        + "bodyVars: [" + bodyVars + "]");

    //Get XmlHttpRequest object.
    var xmlHttp = this._getXmlHttpRequest();

    //Define event handler for request completion
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState != 4 || callBackFunction == null) {  //Still waiting
        return;
      }

      //Request complete. Retrieve response and send to callBack function.
      AjaxCaller.pendingResponseCount--;

      AjaxCaller._debug("Call to: " + url + "\n" +
                  "Returned complete!\n\n" +
                  "Pending Response Count: [" + AjaxCaller.pendingResponseCount + "]\n" +
                  "XmlHttpRequest Count: [" + AjaxCaller.xmlHttpObjects.length + "]\n" +
                  "xmlHttp.readyState: [" + xmlHttp.readyState + "]");

      if (!callBackFunction) {  //Problem accessing callBack function.
        AjaxCaller._error("Problem accessing call back function!");
        return;
      }

      var content = (returnXml) ? xmlHttp.responseXML : xmlHttp.responseText;
      callBackFunction(content);
    };

    xmlHttp.open(requestMethod, url, true);
    switch(requestMethod) {
    case "GET":
      xmlHttp.send(null);
      this.pendingResponseCount++;
      break;

    case "POST":
      xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      xmlHttp.send(bodyVars);
      this.pendingResponseCount++;
      break;
    }
  },

  /*****************
    Attempts to return an unused XmlHttpRequest object. If none exists, 
    creates and returns new XmlHttpRequest object.
  ******************/
  _getXmlHttpRequest : function() {
    var xmlHttp = null;

    for (n=0; n<this.xmlHttpObjects.length; n++) {
      if (this.xmlHttpObjects[n].readyState == 0 || this.xmlHttpObjects[n].readyState == 4) {
        xmlHttp = this.xmlHttpObjects[n];
        xmlHttp.abort();
        break;  //Break out of loop.
      }
    }

    if (xmlHttp == null) {
      xmlHttp = this._createXmlHttpRequest();
      this.xmlHttpObjects.push(xmlHttp);
    }

    this._debug("Getting XmlHttpRequest object.\n" +
                "Pending Response Count: [" + this.pendingResponseCount + "]\n" +
                "XmlHttpRequest Count: [" + this.xmlHttpObjects.length + "]\n" +
                "xmlHttp.readyState: [" + xmlHttp.readyState + "]");

    return xmlHttp;
  },

  /******************
    Iterates through associative array and generates a string of key=value pairs
    separated by '&'.
    - vars : Associative array containing array["key"] = value pairs.
  *******************/
  _createVarsString : function(vars) {
    if (vars instanceof Array == false) {
      return "";
    }

    var varsString = "";
    for (key in vars) {
   	  /* Added for replacing .(Comma) to # to prevent from begin replaced with _(under score) by PHP */
      //varsString+= "&" + key + "=" + escape(vars[key]);
      varsString+= "&" + key.replace('.', '#') + "=" + escape(vars[key]);
    }

    //Remove initial '&' from varsString.
    if (varsString.length > 0) {
      varsString = varsString.substring(1);
    }

    return varsString;
  },

  /*****************
    Creates and returns a new instance of XmlHttpRequest object compatible with all browsers.
  ******************/
  _createXmlHttpRequest : function() {
    try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
    try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
    try { return new XMLHttpRequest(); } catch(e) {}
    alert("XMLHttpRequest not supported");
    return null;
  },

  /*****************
    Show debug messages if debug mode is true.
  ******************/
  _debug : function(message) {
    if (this.debugMode) {
      alert("DEBUG MODE (AjaxCaller.js):\n\n" + message);
    }
  },

  /*****************
    Show error messages if debug mode is true.
  ******************/
  _error : function(message) {
    if (this.debugMode) {
      alert("ERROR (AjaxCaller.js):\n\n" + message);
    }
  }
}

