var ajaxCaller = {

  shouldDebug: false,
  shouldEscapeVars: false,
  shouldMakeHeaderMap: true,

  calls : new Array(),
  pendingResponseCount : 0,

   /**************************************************************************
      PUBLIC METHODS
   *************************************************************************/

  getXML: function(url, callbackFunction) {
    this.get(url, null, callbackFunction, true, null);
  },

  getPlainText: function(url, callbackFunction, callingContext) {
    this.get(url, null, callbackFunction, false, callingContext);
  },
	
	getPlainText_Params: function(url, callbackFunction, callingContext,arrParams) {
    this.get(url, null, callbackFunction, false, callingContext, arrParams);
  },

  postForPlainText: function(url, vars, callbackFunction,arrParams,callingContext) {
    this.postVars(url, vars, null, callbackFunction, false,
                    callingContext,arrParams, "POST", null, null, null);
  },

  postForXML: function(url, vars, callbackFunction) {
    this.postVars(url, vars, null, callbackFunction, true,
                    null,null, "POST", null, null, null);
  },

  get: function(url, urlVars, callbackFunction, expectingXML, callingContext, arrParams) {
    this._callServer(url, urlVars, callbackFunction, expectingXML,
                    callingContext, "GET", null, null, null,arrParams);
  },

  postVars:
    function(url, bodyVars, optionalURLVars, callbackFunction, expectingXML,
             callingContext,arrParams) {
      this._callServer(url, optionalURLVars, callbackFunction, expectingXML,
                      callingContext, "POST", bodyVars, null, null,arrParams);
  },

  postBody:
    function(url, optionalURLVars, callbackFunction, expectingXML,
             callingContext, bodyType, body) {
      this._callServer(url, optionalURLVars, callbackFunction, expectingXML,
                      callingContext, "POST", null, bodyType, body,null);
  },

  putBody:
    function(url, optionalURLVars, callbackFunction, expectingXML,
             callingContext, bodyType, body) {
      this._callServer(url, optionalURLVars, callbackFunction, expectingXML,
                      callingContext, "PUT", null, bodyType, body,null);
  },

  options:
    function(url, optionalURLVars, callbackFunction, expectingXML,
             callingContext, bodyType, body) {
      this._callServer(url, optionalURLVars, callbackFunction, expectingXML,
                      callingContext, "OPTIONS", null, bodyType, body,null);
  },

  trace:
    function(url, optionalURLVars, callbackFunction, expectingXML,
             callingContext, bodyType, body) {
      this._debug("trace");
      this._callServer(url, optionalURLVars, callbackFunction, expectingXML,
                      callingContext, "TRACE", null, bodyType, body,null);
  },

  deleteIt: function(url, urlVars, callbackFunction,
                     expectingXML, callingContext) {
    this._callServer(url, urlVars, callbackFunction, expectingXML,
                    callingContext, "DELETE", null, null, null,null);
  },

  head: function(url, urlVars, callbackFunction, expectingXML, callingContext)
  {
    this._callServer(url, urlVars, callbackFunction, expectingXML,
                    callingContext, "HEAD", null, null, null,null);
  },

  /**************************************************************************
     PRIVATE METHODS
  *************************************************************************/

  _callServer: function(url, urlVars, callbackFunction, expectingXML,
                       callingContext, requestMethod, bodyVars,
                       explicitBodyType, explicitBody,arrParams) {
    if (urlVars==null) {
      urlVars = new Array();
    }

    this._debug("_callServer() called. About to request URL\n"
                + "call key: [" + this.calls.length + "]\n"
                + "url: [" + url + "]\n"
                + "callback function: [" + callbackFunction + "]\n"
                + "treat response as xml?: [" + expectingXML + "]\n"
                + "Request method?: [" + requestMethod + "]\n"
                + "calling context: [" + callingContext + "]\n"
                + "explicit body type: [" + explicitBodyType + "]\n"
                + "explicit body: [" + explicitBody + "]\n"
                + "urlVars: [" + util.describe(urlVars) + "]\n"
                + "bodyVars: [" + util.describe(bodyVars) + "]"
              );

    var xReq = this._createXMLHttpRequest();
    xReq.onreadystatechange = function() {
      ajaxCaller._onResponseStateChange(call,arrParams);
    }

    var call = {xReq: xReq,
                callbackFunction: callbackFunction,
                expectingXML: expectingXML,
                callingContext: callingContext,
                url: url};

    /*if (urlVars!=null) {
      var urlVarsString = this._createHTTPVarSpec(urlVars);
      if (urlVarsString.length > 0) { // TODO check if appending with & instead
        url += "?" + urlVarsString;
      }
    }*/
	
	if(url.indexOf("?") == -1)
		url=url + "?sid=" + Math.random();
	else
		url=url + "&sid=" + Math.random();
		
    xReq.open(requestMethod, url, true);
		xReq.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" ); 
		xReq.setRequestHeader( "Pragma", "no-cache" );
		xReq.setRequestHeader("Cache-Control","no-cache, must-revalidate, no-store, max_age=0");

		
    if (   requestMethod=="GET"
        || requestMethod=="HEAD"
        || requestMethod=="DELETE") {
      this._debug("Body-less request to URL " + url);
      xReq.send(null);
      return;
    }

    if (   requestMethod=="POST"
        || requestMethod=="PUT"
        || requestMethod=="OPTIONS"
        || requestMethod=="TRACE") {
      bodyType = null;
      body = null;
      if (explicitBodyType==null) { // It's a form
        bodyType = 'application/x-www-form-urlencoded; charset=UTF-8';
        body = this._createHTTPVarSpec(bodyVars);
      } else {
        bodyType = explicitBodyType;
        body = explicitBody;
      }
      this._debug("Content-Type: [" + bodyType + "]\nBody: [" + body + "].");
      xReq.setRequestHeader('Content-Type',  bodyType);
      xReq.send(body);
      return;
    }

    this._debug("ERROR: Unknown Request Method: " + requestMethod);


  },

  // The callback of xmlHttpRequest is a dynamically-generated function which
  // immediately calls this function.
  _onResponseStateChange: function(call,arrParams) {
    xReq = call.xReq;

    if (xReq.readyState < 4) { //Still waiting
      return;
    }

    if (xReq.readyState == 4) { //Transmit to actual callback
			if (xReq.status == 200){
      this._debug("Call " + util.describe(call)
                + " with context [" + call.callingContext+"]"
                + " to " + call.url + " has returned.");
      callbackFunction = call.callbackFunction;
      if (!callbackFunction) { // Maybe still loading, e.g. in another JS file
        setTimeout(function() {
          _onResponseStateChange(call);
        }, 100);
      }
      var content = call.expectingXML ? xReq.responseXML : xReq.responseText;
      responseHeaders = xReq.getAllResponseHeaders();
      headersForCaller = this.shouldMakeHeaderMap ?
        this._createHeaderMap(responseHeaders) : responseHeaders;
      callbackFunction(content, call.callingContext, headersForCaller,arrParams);
    }
		}

    call = null; // Technically the responsibility of GC
    this.pendingResponseCount--;

  },

  // Browser-agnostic factory function
  _createXMLHttpRequest: function() {
    if (window.XMLHttpRequest) {
      return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      return new ActiveXObject('Microsoft.XMLHTTP')
    } else {
      _error("Could not create XMLHttpRequest on this browser");
      return null;
    }
  },

  _createHTTPVarSpec: function(vars) {
      var varsString = "";
      for( key in vars ) {
        var value = vars[key];
        if (this.shouldEscapeVars) {
          escapePlusRE =  new RegExp("\\\+");
          value = value.replace(escapePlusRE, "%2B");
        }
        varsString += '&' + key + '=' + value;
      }
      if (varsString.length > 0) {
        varsString = varsString.substring(1); // chomp initial '&'
      }
      this._debug("Built var String: " + varsString)
      return varsString;
   },

  /* Creates associative array from header type to header */
  _createHeaderMap: function(headersText) {
    extractedHeaders = headersText.split("\n");
    delete extractedHeaders[extractedHeaders.length]; // Del blank line at end
    headerMap = new Array();
    for (i=0; i<extractedHeaders.length-2; i++) {
      head = extractedHeaders[i];
      fieldNameEnding = head.indexOf(":");
      field = head.substring(0, fieldNameEnding);
      value = head.substring(fieldNameEnding + 2, head.length);
      value = value.replace(/\s$/, "");
      headerMap[field] = value;
    }
    return headerMap;
  },

  _debug: function(message) {
      if (this.shouldDebug) {
        alert("AjaxJS Message:\n\n" + message);
      }
  },

  _error: function(message) {
      if (this.shouldDebug) {
        alert("AjaxJS ERROR:\n\n" + message);
      }
  }

};


function loadData(text,callingContext,headers,arrParams)
{
	if (text.replace(/ /g,"") != "")
	{
		window.document.getElementById(callingContext).innerHTML = text;
		setJSFunctions(callingContext,text);
	}
}

function loadDataTFS(text,callingContext,headers,arrParams)
{
	if (text.replace(/ /g,"") != "" && text.indexOf("FILEREADERROR") == -1)
	{
		window.document.getElementById(callingContext).innerHTML = text;
		setJSFunctions(callingContext,text);
	}
	else if (text.indexOf("FILEREADERROR") != -1){
		ajaxCaller.getPlainText_Params(arrParams[0],loadDataTFS,callingContext, arrParams);	
	}
}

function loadDataMZ(text,callingContext,headers,arrParams)
{	
	var tabnum=callingContext.substring(callingContext.indexOf("_")+1,callingContext.indexOf("_")+2);
	//alert(window.document.getElementById("tabsystitle_"+tabnum+"_"+callingContext.substring(callingContext.indexOf("_")+3)).className);
	if(window.document.getElementById("tabsystitle_"+tabnum+"_"+callingContext.substring(callingContext.indexOf("_")+3)).className.indexOf(" on") == -1){
		window.document.getElementById("tabsyscontent_"+tabnum+"_"+callingContext.substring(callingContext.indexOf("_")+3)).className = 'notgone';
		return;
	}
	for(i=1;i<arrParams[0];i++){
			window.document.getElementById("tabsyscontent_"+i+"_"+callingContext.substring(callingContext.indexOf("_")+3)).className = (i == tabnum) ? "notgone" : "gone";
	}
	if (text.replace(/ /g,"") != "")
	{
		if (arrParams[1] == "fullHeight")
			htmlContent = text;
		else
			htmlContent = "<div style='height:360px;width:100%;overflow-y:auto;overflow-x:visible'>" + text + "</div>";
		window.document.getElementById(callingContext).innerHTML = htmlContent;
	}
	try { window.document.getElementById("MyZawyaloadingimage").className="gone"; window.document.getElementById(callingContext).className = 'notgone'; } catch(e) {};
	//window.document.getElementById(callingContext.replace(/content/, "tabData") ).className="notgone";	
	if((arrParams[1] == "fullHeight" && tabnum==1) || (arrParams[1] != "fullHeight" && tabnum==2) || tabnum==3)
		window.setTimeout('toolTip.setup()',300);
}

function loadDataMZ_old(text,callingContext,headers,arrParams)
{	
	var tabnum=callingContext.substring(callingContext.indexOf("_")-1,callingContext.indexOf("_"));
	if(window.document.getElementById("tabTitle"+tabnum+"_"+callingContext.substring(callingContext.indexOf("_")+1)).className == "unselectedTab"){
		return;
	}
	for(i=1;i<arrParams[0];i++){
		window.document.getElementById("tabData"+i+"_"+callingContext.substring(callingContext.indexOf("_")+1)).className="gone";
	}
	if (text.replace(/ /g,"") != "")
	{
		if (arrParams[1] == "fullHeight")
			htmlContent = text;
		else
			htmlContent = "<div style='height:360px;width:100%;overflow-y:auto;overflow-x:visible'>" + text + "</div>";
		window.document.getElementById(callingContext).innerHTML = htmlContent;
	}
	window.document.getElementById("MyZawyaloadingimage").className="gone";
	window.document.getElementById(callingContext.replace(/content/, "tabData") ).className="notgone";	
	if((arrParams[1] == "fullHeight" && tabnum==1) || (arrParams[1] != "fullHeight" && tabnum==2) || tabnum==3)
		window.setTimeout('toolTip.setup()',300);
}

function loadLiveZDJData(text,callingContext,headers,arrParams)
{
	if (text.replace(/ /g,"") != "" && global_dj_refresh == true)
	{
		window.document.getElementById(callingContext).innerHTML = text;
		setJSFunctions(callingContext,text);
	}
	else
		global_dj_refresh = false;
}

function loadLiveMNData(text,callingContext,headers,arrParams)
{
	if (text.replace(/ /g,"") != "" && global_lm_refresh == true)
	{
		window.document.getElementById(callingContext).innerHTML = text;
		setJSFunctions(callingContext,text);
	}
	else
		global_lm_refresh = false;
}
