/* ---------------------------------------------------------------------- */
/*  
  Ajax compatibility test and IE-retrofit library, ajaxCap.js
  (c) Copyright 2005, e-numera, Inc.
*/


// Error message if Ajax is not compatible
var ajaxIncompatibleReason = "";

// function isAjaxCompat()
// Returns true if the current user agent supports XMLHttpRequest
function isAjaxCompat() {
  if (window.XMLHttpRequest)
    return true
  else
    return false;
}

/* Everything below this point should be treated as PRIVATE */

// Internal Flag to determine whether to use alternative ActiveX class
var _usesMsXml2 = false;
var _usesXMLHTTP = false;

if (window.XMLDocument) // Why can't Mozilla create a new XMLDocument() in Javascript?
  function XMLDocument () {
    return document.implementation.createDocument("", "", null);
  }

// Retrofit IE 5+ (or any other browsers) to support
// "standard" XMLHttpRequest constructor
if (!isAjaxCompat()) {

  var _ajax_temp_obj = false;

  // attempt to create the most desireable XMLHTTP class
  try {
    _ajax_temp_obj = new ActiveXObject("Msxml2.XMLHTTP");
    _usesMsXml2 = true;
  }
  catch(e) {
    // That didn't work.  Try alternative class
    try {
      _ajax_temp_obj = new ActiveXObject("Microsoft.XMLHTTP");
      _usesXMLHTTP = true;
    }
    catch (e) {
      ajaxIncompatibleReason = e.message;
    }
  }
  
  // declare constructor
  if (_usesMsXml2) {
    function XMLHttpRequest() {
      return new ActiveXObject("Msxml2.XMLHTTP");
    }
    function XMLDocument() {
      return new ActiveXObject("Msxml2.DOMDocument");
    }
  }
  else if (_usesXMLHTTP) {
    function XMLHttpRequest() {
      return new ActiveXObject("Microsoft.XMLHTTP");
    }
    function XMLDocument() {
      return new ActiveXObject("Microsoft.XMLDOM");
    }
  }

} // if (!isAjaxCompat())
_usesMsXml2 = null;
_usesXMLHTTP = null;

/* ---------------------------------------------------------------------- */
/*  
  Ajax base library, ajaxBase.js
  (c) Copyright 2005, e-numera, Inc.
*/

/* Requires prototype-1.3.1.js */
/*
  To Do:
    handle exceptions
    comments
*/

function AjaxBase() {
  // default HTTP method is GET
  this.httpMethod = "GET";
  this.instanced = true;
}

// Set HTTP method used when AjaxBase is not instantiated
AjaxBase.httpMethod = "GET";

// method AjaxBase.getElements(elements_or_ids)
AjaxBase.getElements = function () {
  if (arguments.length == 1) {
    return document.getElementById(element);
  }
  else {
    var elements = new Array();
    for (var i = 0; i < arguments.length; i++) {
      var element = arguments[i];
      if (typeof element == 'string')
        element = document.getElementById(element);
      elements.push(element);
    }
    return elements;
  }
}

AjaxBase.getParseError = function(xmlDoc) {
  if (!xmlDoc || undefined == xmlDoc.documentElement)
    return "No XML found.";
  if (xmlDoc.parseError) 
    return xmlDoc.parseError != 0 ? "XML Parsing Error: " + xmlDoc.parseError.reason + "\nurl: " + xmlDoc.parseError.url + "\nat " + xmlDoc.parseError.line + ", " + xmlDoc.parseError.linepos + ":\n" + xmlDoc.parseError.srcText : "";
  else if (xmlDoc.documentElement.nodeName == 'parsererror') 
    return xmlDoc.documentElement.firstChild.data + "\n" +  xmlDoc.documentElement.firstChild.nextSibling.firstChild.data;
  else
    return "";
}

// method AjaxBase.getXMLHttpRequest()
AjaxBase._getXMLHttpRequest = function() {
  var xmlReq = new XMLHttpRequest();
  return xmlReq;
}

// method AjaxBase.openXMLHttpRequest(xmlReq, url[, httpMethod[, rscEventHandler]])
AjaxBase._openXMLHttpRequest = function(xmlReq, url, httpMethod, httpData, rscEventHandler, contentType) {
  if (!httpMethod) httpMethod = this.httpMethod;
  if (rscEventHandler) xmlReq.onreadystatechange = rscEventHandler;
  xmlReq.open(httpMethod, url, !!rscEventHandler);
  if (httpMethod == 'POST') 
    if (!contentType)
      xmlReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    else
      xmlReq.setRequestHeader('Content-Type', contentType);
  xmlReq.send(httpMethod == 'POST' ? httpData : null);
  return true;
}

// method AjaxBase.doXMLHttpRequest(url[, httpMethod[, rscEventHandler]])
// Note: This function does not work correctly in IE.  It
// calls the event handler before exiting, causing the current
// object instance to be undefined in the event handler.
// Use getXMLHttpRequest and openXMLHttpRequest instead.
// TO DO: try using setTimeout()
/*
AjaxBase.prototype.doXMLHttpRequest = function(url, httpMethod, rscEventHandler) {
  if (!httpMethod) httpMethod = this.httpMethod;
  var xmlReq = AjaxBase._getXMLHttpRequest();
  if (rscEventHandler) xmlReq.onreadystatechange = rscEventHandler;
  xmlReq.open(httpMethod, url, rscEventHandler != undefined);
  xmlReq.send(null);
  return xmlReq;
}
AjaxBase.doXMLHttpRequest = AjaxBase.prototype.doXMLHttpRequest;
*/

// method AjaxBase.getXML(url[, httpMethod[, httpData[, asyncEventHandler[, asyncErrorHandler]]]])
// asyncEventHandler = function(response[, url[, httpData]]) {}
// asyncErrorHandler = function(url, status) {}
AjaxBase.prototype.getXML = function(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, contentType) {
  return this._getContent(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, true, contentType);
}
AjaxBase.getXML = AjaxBase.prototype.getXML;

// method AjaxBase.getText(url[, httpMethod[, httpData[, asyncEventHandler[, asyncErrorHandler]]]])
// asyncEventHandler = function(response[, url[, httpData]]) {}
// asyncErrorHandler = function(url, status) {}
AjaxBase.prototype.getText = function(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, contentType) {
  return this._getContent(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, false, contentType);
}
AjaxBase.getText = AjaxBase.prototype.getText;

// method AjaxBase.getHTML(url[, httpMethod[, httpData[, asyncEventHandler[, asyncErrorHandler]]]])
// asyncEventHandler = function(response[, url[, httpData]]) {}
// asyncErrorHandler = function(url, status) {}
AjaxBase.prototype.getHTML = function(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, contentType) {
  return this._getContent(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, false, contentType);
}
AjaxBase.getHTML = AjaxBase.prototype.getText;

// method AjaxBase.getJSON(url[, httpMethod[, httpData[, asyncEventHandler[, asyncErrorHandler]]]])
// asyncEventHandler = function(response[, url[, httpData]]) {}
// asyncErrorHandler = function(url, status) {}
AjaxBase.prototype.getJSON = AjaxBase.prototype.getText;
AjaxBase.getJSON = AjaxBase.prototype.getText;

// method AjaxBase.executeScripts(html)
// executes scripts found in html.
// hint: plan to call this in a setTimeout so that any html on which these scripts rely is rendered
AjaxBase.prototype.executeScripts = function(html) {
  // get scripts
  var matches = new RegExp('(?:<script.*?>)((\n|.)*?)(?:<\/script>)', 'img');
  var scripts = html.match(match);  
  // execute them
  for (var i = 0; i < scripts.length; i++)
    eval(scripts[i].match(match)[1]);
}
AjaxBase.executeScripts = AjaxBase.prototype.executeScripts;

AjaxBase.prototype._getContent = function(url, httpMethod, httpData, asyncEventHandler, asyncErrorHandler, isXml, contentType) {
  if (!httpMethod) httpMethod = this.httpMethod;
  var xmlReq = AjaxBase._getXMLHttpRequest();
  if (!asyncEventHandler) {
    AjaxBase._openXMLHttpRequest(xmlReq, url, httpMethod, httpData, false, contentType);
    // TO DO: check status
    // TO DO: return httpData and proxy.xmlReq.responseText if error
    if (isXml)
      return xmlReq.responseXML;
    else
      return xmlReq.responseText;
  }
  else {
    // Create a unique id from url, timestamp, and a random #
    var id = AjaxBase._extractBaseUrl(url) + "-"
      + new Date().getTime().toString() + "-"
      + Math.random().toString();
    var proxy = new _AjaxProxy(id, xmlReq, url, httpData, asyncEventHandler, asyncErrorHandler, isXml);
// TO DO: rewrite this without using proxy and string -> send a JSON object right into function
    var newFunc = "AjaxBase._rscHandler(_AjaxProxy._get_proxy('" + id + "'));";
    xmlReq.onreadystatechange = new Function(newFunc);
    _AjaxProxy._add_proxy(id, proxy);
    xmlReq.open(httpMethod, url, true);
    if (!contentType)
      xmlReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    else
      xmlReq.setRequestHeader('Content-Type', contentType);
    xmlReq.send(httpMethod == 'POST' ? httpData : null);
    return;
  }
}
AjaxBase._getContent = AjaxBase.prototype._getContent;

AjaxBase._extractBaseUrl = function(url) {
  var base = url.split("?")[0];
  var slashPos = base.lastIndexOf("index.html");
  base = base.substr(slashPos >= 0 ? slashPos : 0);
  return base;
}

AjaxBase._rscHandler = function(proxy) {
  var state = proxy.xmlReq.readyState;
  if (state == 4) {
    var status = proxy.xmlReq.status;
    if ((status == 200) || (status == 0)) { // status == 0 for local file
      _AjaxProxy._remove_proxy(proxy.id);
      if (proxy.isXML)
        proxy.callback(proxy.xmlReq.responseXML, proxy.url, proxy.httpData);
      else
        proxy.callback(proxy.xmlReq.responseText, proxy.url, proxy.httpData);
    }
    else { // error status
      _AjaxProxy._remove_proxy(proxy.id);
      // TO DO: return httpData and proxy.xmlReq.responseText
      if (proxy.errorCallback) 
        proxy.errorCallback(proxy.url, status, proxy.httpData);
    }
  }
}

// AjaxProxy:
// AjaxProxy allows stateful operation even without instantiating an object.
// e.g. "AjaxBase.getXML(...)" instead of "var ajax = new AjaxBase(); ajax.getXML(...)"
function _AjaxProxy(id, xmlReq, url, httpData, callback, errorCallback, isXML) {
  this.id = id;
  this.url = url;
  this.httpData = httpData;
  this.xmlReq = xmlReq;  
  this.callback = callback;
  this.errorCallback = errorCallback;
  this.isXML = isXML;
}

_AjaxProxy._ajax_proxies = new Object();

_AjaxProxy._add_proxy = function(id, proxy) {
  _AjaxProxy._ajax_proxies[id] = proxy;
}

_AjaxProxy._get_proxy = function(id) {
  return _AjaxProxy._ajax_proxies[id];
}

_AjaxProxy._remove_proxy = function(id) {
  _AjaxProxy._ajax_proxies[id] = null;
}

