////////////////////////////////////////////////////////////////////////////////
// Main Wrapper Method :
////////////////////////////////////////////////////////////////////////////////
function webRequest(url, username, password, synchronous, readyFunction, sendData, useCache, timeout) {
  var request = new WebRequest(url, username, password, synchronous, readyFunction, sendData, useCache, timeout);
  return request.sendRequest();
}

////////////////////////////////////////////////////////////////////////////////
// Utility Methods :
////////////////////////////////////////////////////////////////////////////////
function addTimeStampToURL(url) {
  // Add a timestamp to the URL to guarantee no caching.
  // XXX TO DO: check for the "#" character in the URL and make
  // sure it remains at the end of the URL.

  ts = new Date();

  // Find any "_cache_ts" parameters and replace with empty strings
  re =/_cache_ts=\d+&?/g;
  url = url.replace(re, '');

  if (url.indexOf('?') < 0) {
    url += '?';
  } else {
    url += '&';
  }
  url += '_cache_ts=' + ts.getTime();
  
  // Other replace may have left "?&" or "&&" in the url. Replace
  // them as appropriate.
  url = url.replace(/&&/g, '&');
  url = url.replace(/\?&/g, '?');
  
  return url;
}

// Methods called anonymously to check for state change and send data :
function readyStateChange(webRequest) {
  // Called when there is a change in the state of the request
  if (webRequest.req.readyState == 4) webRequest.processResponseData();
};

function sendRequestData(webRequest) {
  //dlog && dlog.logStringMessage("[WebRequest.sendRequestData] Sending " + webRequest.sendData);
  webRequest.req.send(webRequest.sendData);
}


////////////////////////////////////////////////////////////////////////////////
// Main Web Request object :
////////////////////////////////////////////////////////////////////////////////
function WebRequest(url, username, password, synchronous, readyFunction, sendData, useCache, timeout) {
  this.url = url; // Required.
  this.username = username || '';
  this.password = password || '';
  if (synchronous == null) synchronous = true; // Default to synchronous if not specified as true/false
  this.synchronous = synchronous
  this.useCache = useCache ? true:false;
  this.readyFunction = readyFunction;
  this.timeout = timeout ? timeout:10;
  this.sendData = sendData ? sendData:'';
  this.req = null; // Request doesn't exist yet :
  this.method = sendData ? 'POST' : 'GET';
}

WebRequest.prototype.getURL = function() {
  // Get the url for this request, adding a timestamp if needed.
  if (this.useCache) return addTimeStampToURL(this.url);   
  return url;
}

WebRequest.prototype.setHeaders = function() {
  if (!this.useCache) this.req.setRequestHeader("Cache-Control", "no-cache");
  if (this.sendData) this.req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // XXX Required ?
}

WebRequest.prototype.getResponseType = function() {  
  contentType = this.req.getResponseHeader("Content-Type");
  if (contentType) return contentType.split(';')[0]; // eg. 'text/xml'.  The split removes encoding.
  return '';
}

WebRequest.prototype.processResponseData = function() {
  data = this.getResponseData();
  if (this.readyFunction) {
    return this.readyFunction(data);
  }
  return data;
}

WebRequest.prototype.getResponseData = function() {
  return this.req.responseText;

  //  contentType = this.getResponseType();
  //  if ((contentType == 'text/html')||(contentType == 'text/plain')) {
  //  return this.req.responseText;
  //} else if ((contentType == 'text/xml') && (this.req.responseXML)) {
  //    return this.req.responseXML.documentElement;
  //}
  //dlog && dlog.logStringMessage("[WebRequest.getResponseData] Unknown Content Type : '" + contentType + "' for url = '" + this.url + "'.");
  //return null;
}

WebRequest.prototype.sendRequest = function() {  
  // Main send method.

  this.req = new XMLHttpRequest();
  var self = this; // Need a different variable for use in the anonymous functions otherwise 'this' becomes the anonymous function.

  if (!this.synchronous) this.req.onreadystatechange = function () {readyStateChange(self);};

  //dlog && dlog.logStringMessage("[WebRequest.sendRequest Opening " + this.url + " with " + this.username + ":" + this.password);
  this.req.open(this.method, this.url, !this.synchronous, this.username, this.password); // Async == true.
  this.setHeaders();

  if (!this.synchronous) {
    window.setTimeout(function () { sendRequestData(self);}, this.timeout);
    return; // Return from here with no data
  }

  // Send the data, and get the results
  try {
    this.req.send(this.sendData);
  } catch(e) {
    return; // XXX Should log error
  }
  return this.getResponseData();
}

