
function AJAX(url) {
 /**
  * Handle to the xmlhttp object
  * @scope private
  */
 this.xmlhttp = null;

 /**
  * Indicator on whether a call (get or post) is currently in progress. Multiple calls cannot be placed
  * at the same time using the same instance
  * @scope inProcess
  */
 this.inProcess = false;

 /**
  * Variables used to compute time taken for request to complete
  * @scope private
  */
  this.startTime = null;

 /**
  * Variables used to compute time taken for request to complete
  * @scope private
  */
  this.endTime = null;

 /**
  * User defined handler. Must extend DefaultAJAXHandler
  * @scope public
  */
 this.userHandler = null;


 /**
  * URL to which the call is being made
  * @scope private
  */
 this.url = url;

 /**
  * Query string that will be passed with the request
  * @scope private
  */
 this.queryString = null;

 /**
  * initialize the object
  */
 this.init();
}

AJAX.prototype = {
  /**
   * Initializes the AJAX object
   * @scope private
   */
  init: function() {
    this.xmlhttp = getHttpObject();
  },

  timeTaken: function() {
    return this.endTime.getTime() - this.startTime.getTime();
  },

  /**
   * Aborts the current request. If no call is in progress nothing is done
   * @scope public
   */
  abort: function() {
    if (this.inProcess) {
      this.xmlhttp.abort();
      this.inProcess = false;
      this.endTime = new Date();
    }
  },

   /**
    * @param The id element to update with the contents from the URI
    * @scope public
    */
  performAsyncGetAndUpdateHTML: function(elementID) {
    var urlWithQueryParams = this.url;
    if (this.inProcess) {
      throw "A call is in progress";
    }
    if (this.queryString) {
      urlWithQueryParams += "?" + this.queryString;
    }
    this.xmlhttp.open("GET", urlWithQueryParams, true);
    //prevent caching of pages with the same url
    this.xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
    if (!this.userHandler) {
      this.userHandler = new DefaultContentReplacementHandler(elementID);
    }

    var self = this;
    //register the callback
    this.xmlhttp.onreadystatechange = function() {
      self.stateChangeCallback(self);
    }

    //set the flag indicating the call is in process
    this.inProcess = true;

    this.startTime = new Date();

    //send the request
    this.xmlhttp.send(null);
  },

  stateChangeCallback: function(ajaxClient) {
    switch(ajaxClient.xmlhttp.readyState) {
      //Reqest hasn't been made
      case 1:
        try {
          if (ajaxClient.userHandler) {
            ajaxClient.userHandler.onInit();
          }
        } catch (e) {/* Handler method not defined */}
        break;
      //Contact established but nothing has been downloaded
      case 2:
        try {
          // Check for HTTP status 200
          if (ajaxClient.xmlhttp.status != 200) {
            ajaxClient.userhandler.onError(ajaxClient.xmlhttp.status, ajaxClient.xmlhttp.statusText);
            // Abort the request
            ajaxClient.abort();
            // Call no longer in progress
            ajaxClient.inProcess = false;

            ajaxClient.endTime = new Date();
          }
        } catch (e) {/* Handler method not defined */}
        break;

      // Called multiple while downloading in progress
      case 3:
         // Notify user handler of download progress
         try {
           // Get the total content length
           // -useful to work out how much has been downloaded
           try {
             var contentLength = ajaxClient.xmlhttp.getResponseHeader("Content-Length");
             var isXML = (ajaxClient.xmlhttp.getResponseHeader("Content-Type").indexof("xml") != -1);
           } catch (e) {
             var contentLength = NaN;
             var isXML = false;
           }
           // Call the progress handler with what we've got
           if (isXML) {
             ajaxClient.userHandler.onProgress(ajaxClient.xmlhttp.responseXML, contentLength);
           } else {
             ajaxClient.userHandler.onProgress(ajaxClient.xmlhttp.responseText, contentLength);
           }
         } catch (e) { /* Handler method not defined */ }
           break;
       // Download complete
       case 4:
         try {
           try {
             var isXML = (ajaxClient.xmlhttp.getResponseHeader("Content-Type").indexof("xml") != -1);
           } catch(e1) {
             var isXML = false;
           }
           if (isXML) {
             ajaxClient.userHandler.onLoad(ajaxClient.xmlhttp.responseXML);
           } else {
             ajaxClient.userHandler.onLoad(ajaxClient.xmlhttp.responseText);
           }
         } catch (e) {/* Handler method not defined */}
         finally {
           // Call no longer in progress
           ajaxClient.inProcess = false;
           ajaxClient.endTime = new Date();
           try {
             ajaxClient.userHandler.setTimeTaken(ajaxClient.timeTaken());
           } catch (e) {/* Handler method not defined */}
         }
         break;
    }
  }
}

// A user defined handler to response to the XMLHTTPRequest
function DefaultAJAXHandler() {}

DefaultAJAXHandler.prototype = {
    onInit: function() {
        alert("About to send request<br>");
    },
    onError: function(status,statusText) {
        alert("Error: "+status+": "+statusText+"<br>");
    },
    onProgress: function(responseText,length) {
        alert("Downloaded "+responseText.length+" of "+length+"<br>");
    },
    onLoad: function(result) {
        alert("<pre>"+result+"</pre>");
    },
    setTimeTaken: function(time) {
      alert("<pre>"+result+" ms</pre>");
    }
}

function DefaultContentReplacementHandler(elementID) {
  this.oElement = document.getElementById(elementID);
  if (oElement==null) alert("Could not find elementID: " + elementID + " to replace content of.");
  this.processingMessage = "Processing request <br>";
  this.timeTaken = null;
}

function DefaultContentReplacementHandler(elementID,processingMessage) {
  this.oElement = document.getElementById(elementID);
  this.processingMessage = processingMessage;
  this.timeTaken = null;
}

DefaultContentReplacementHandler.prototype = {

    onInit: function() {
        if (this.processingMessage!=null)
          this.oElement.innerHTML = this.processingMessage;
    },

    onError: function(status,statusText) {
        this.oElement.innerHTML = "Error: "+status+": "+statusText+"<br>";
    },
    onProgress: function(responseText,length) {
        this.oElement.innerHTML = "Downloaded "+responseText.length+" of "+length+"<br>";
    },
    onLoad: function(result) {
        this.oElement.innerHTML = result;
    },
    setTimeTaken: function(time) {
      this.timeTaken = time;
    }
}

function FormHelper() {}

FormHelper.prototype = {
  getFormDataAsQueryString: function(formName) {
    var data = "";
    if (formName == null) {
      return null;
    }
    var form = document.forms[formName];
    if (form == null) {
      return null;
    }
    var formElement;
    var key;
    var type;
    for (var i = 0 ; i < form.elements.length; i++) {
      formElement = form.elements[i];
      key = form.elements[i].name;
      type = form.elements[i].type;
      if (type == 'button') {
        continue;
      }
      if (type == 'select-multiple' || type == 'select-one') {
        for (var j = 0 ; j < formElement.options.length; j++) {
          if (formElement.options[j].selected) {
            data += key + "=" + escape(formElement.options[j].value) + "&";
          }
        }
      } else if ((type =='checkbox') || (type=='radio')) {
        if (formElement.checked) {
            data += key + "=" + formElement.value + "&";
        }
      } else {
        data += key + "=" + formElement.value + "&";
      }
    }
    //remove the trailing '&'
    if (data.length > 1) {
      data = data.substring(0, data.length -1);
    }
    if (data == "") {
      data = null;
    }
    return data;
  }
}


    function getHttpObject() {
      var xmlhttp = false;
      try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		  } catch (e) {
		 	  try {
		 	    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			  } catch (E) {
			    xmlhttp = false;
			  }
		  }
		  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
		    xmlhttp = new XMLHttpRequest();
		  }
      return xmlhttp;
    }



    function findAJAXParent(caller) {
      callerParent = caller;
      while (callerParent!=null) {
        if (callerParent.ajaxId!=null)
          break;
        callerParent = callerParent.parentElement;
      }
      return callerParent;
    }

    function loadDivContent(url, divName) {
        replaceDivContent(url,divName,'<img src="images/animatedGIFs/loading2.gif" border="0"><br>Loading...');
    }

    function replaceDivContent(url, divName, processingMessage) {
      if (divName!=null) {
        var genericHandler = new DefaultContentReplacementHandler(divName,processingMessage);
        genericHandler.processingMessage = processingMessage;
        genericAJAX = new AJAX(url);
        genericAJAX.userHandler = genericHandler;
        genericAJAX.performAsyncGetAndUpdateHTML();
      }
      else
        alert ("divName cannot be null");
    }

    function performAsyncGet(form, url, preProcessFunction, callbackFunction) {
      preProcessFunction;
      submitData("GET", form, url, callbackFunction, true);
    }

    function performAsyncPost(form, url, preProcessFunction, callbackFunction) {
      preProcessFunction;
      submitData("POST", form, url, callbackFunction, true);
    }

    function performSyncGet(form, url, preProcessFunction, callbackFunction) {
      preProcessFunction;
      submitData("GET", form, url, callbackFunction, false);
    }

    function performSyncPost(form, url, preProcessFunction, callbackFunction) {
      preProcessFunction;
      submitData("POST", form, url, callbackFunction, false);
    }

    function submitData(method, form, url, callbackFunction, synchronous) {
      //http object cannot be reused
      var xmlHttp = getHttpObject();

      if (xmlHttp) {
        xmlHttp.onreadystatechange = function processResults() {

          if (xmlHttp.readyState == 4) {
            if (xmlHttp.status == 200) {

              if (xmlHttp.getResponseHeader("JCSAUTHENTICATIONFAILURE") == "true") {
                alert ("Authorization Failure.");
                window.location = "LoginPage.jsp";
                return;
              }

              var response = null;
              if(xmlHttp.getResponseHeader('Content-Type').indexOf('xml') != -1) {
                response = xmlHttp.responseXML;
              } else {
                response = xmlHttp.responseText;
              }
              callbackFunction(response);
            } else {
               alert ("xmlHttp.status: '" + xmlHttp.status + "'");
               //alert ("xmlHttp.responseText: '" + xmlHttp.responseText + "'");
               //alert("Error: " + xmlHttp.statusText);
               callbackFunction(response);
            }
            xmlHttp = null;
          }
        };

        try {
          var formdata = getFormData(form);
          var sendData = formdata;

          //Append request parameters to the URL for GET
          if (method == 'GET' && formdata != null) {
            url += "?" + data;
            sendData = null;
          }

          xmlHttp.open(method, url, synchronous);
          if (formdata != null) {
            xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xmlHttp.setRequestHeader('Content-length', sendData.length);
            xmlHttp.setRequestHeader('Connection', 'close');
          }
          xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
          xmlHttp.send(sendData);
        } catch (e) {
          alert("There was an error getting data: " + e);
        }
      } else {
        alert("Unsupported browser");
      }
    }


    function getFormData(formName) {
      var data = "";
      if (formName == null) {
        return null;
      }
      var form;
      if (typeof formName == "string") {
        form = document.forms[formName];
        if (form == null) alert ("Can't find form by name: '" + formName + "'");
      } else {
        form = formName;
      }

      var formElement;
      var key;
      var type;
      for (var i = 0 ; i < form.elements.length; i++) {
        formElement = form.elements[i];
        key = form.elements[i].name;
        type = form.elements[i].type;
        if (type == 'button') {
          continue;
        }
        if(type == 'select-multiple' || type == 'select-one') {
          for (var j = 0 ; j < formElement.options.length; j++) {
            if (formElement.options[j].selected) {
              data += key + "=" + escape(formElement.options[j].value) + "&";
            }
          }
        } else if ((type =='checkbox') || (type=='radio')) {
          if (formElement.checked) {
              data += key + "=" + encodeURIComponent(formElement.value) + "&";
          }
        } else {
          data += key + "=" + encodeURIComponent(formElement.value) + "&";
        }
      }
      //remove the trailing '&'
      if (data.length > 1) {
        data = data.substring(0, data.length -1);
      }
      if (data == "") {
        data = null;
      }
      return data;
    }

    function replaceSectionContent(sectionID, html) {
      var obj = document.getElementById(sectionID);
      if (obj!= null) 
      {
      	obj.innerHTML = html
      }
    }

    function collapseSection(sectionID) {
      var obj = document.getElementById(sectionID);
      obj.style.display = 'none';
    }

    function restoreSection(sectionID) {
       var obj = document.getElementById(sectionID);
       obj.style.display = 'block';
    }

//Invokes a function passed in as a string. Listed below is an example of how to use the function
//function RunTest() {
//    alert(InvokeFunction("TestFunc", new DummyObject(false), "My Test", 123, false, RunTest));
//}
//
//function TestFunc(objDummy) {
//
//    var sMsg = "TestFunc called with " + arguments.length + " arguments.\n\n";
//    for (var nCount = 0; nCount < arguments.length; nCount++) {
//        sMsg += nCount + ". " + typeof(arguments[nCount]) + " - " + arguments[nCount] + "\n";
//    }
//    alert(sMsg);
//    return objDummy.x;
//}

  function InvokeFunction(Handler) {
    // Calls Handler and passes any additional parameters
    try {
        if ((typeof Handler != "string") && (typeof Handler != "function")) {
            throw new Error("Invalid Handler object specified.");
        }
        else {
            var aArgs = new Array;
            var bBuildFunction = (typeof Handler == "string");
            var sCode = "";
            // Store the arguments
            for (var nCount = 1; nCount < arguments.length; nCount++) {
                aArgs[nCount - 1] = arguments[nCount];
                if (bBuildFunction == true) {
                    if (nCount > 1) {
                        sCode += ", ";
                    }
                    sCode += "arguments[" + (nCount - 1) + "]";
                }
            }
            var objFunc = null;
            if (typeof Handler == "string") {
                // Build the dynamic code to run
                sCode = "return " + Handler + "(" + sCode + ");";
                // Create a new function from the code built
                objFunc = new Function(sCode);
            }
            else if (typeof Handler == "function") {
                // Take a pointer to the function
                objFunc = Handler;
            }
            // Run the function with the arguments
            return objFunc.apply(this.caller, aArgs);
        }
    } catch(e) {
        throw new Error("Failed to invoke function " + Handler + ".\n\n" + e.message);
    }
  }

