/**
 * HttpClient is a javascript client which can execute HTTP conversations
 * with a remote server.  It supports GET and POST requests.  When the
 * communication method is created, one success and one failure callback
 * method can be provided.  Once the request is complete, the appropriate
 * method is called.
 *
 * References: 
 *   http://developer.apple.com/internet/webcontent/xmlhttpreq.html
 *   http://www.mojavelinux.com/wiki/doku.php?id=scriptsandbox
 *
 */
msieXmlHttpSuffix=".XmlHttp";

function setHtml(id, html) {
  if (!document.getElementById) return;
  var ele = document.getElementById(id);
  if (ele == null)
    return;
  ele.innerHTML='';
  ele.innerHTML=html;
}
function waitPointer(ele) {
  if (!document.getElementById) return;
  document.getElementById(ele).style.cursor = 'wait';
}
function defaultPointer(ele) {
  if (!document.getElementById) return;
  document.getElementById(ele).style.cursor = 'default';
}

function errorMsg(msg, e) {
  return msg + "\nError name: " + e.name + "\nError message: " + e.message;
}
  
function getHttpControlPrefix(debug) {
  if (getHttpControlPrefix.prefix) {
    return getHttpControlPrefix.prefix;
  }
  var prefixes = [ "Msxml2", "Microsoft", "Msxml3", "Msxml" ];
  var obj;
  for (var i=0; i<prefixes.length; i++) {
    try {
      obj = new ActiveXObject(prefixes[i] + msieXmlHttpSuffix);
      if (obj != null) {
        getHttpControlPrefix.prefix = prefixes[i];
        return getHttpControlPrefix.prefix;
      }
    } catch (ex) {};
  }
  return null;
}

function HttpClient(debug) {
  this.debug = (debug != null ? debug : false);
  this.XMLHttp = false;
  //for ie7 and moz
  if (window.XMLHttpRequest) {
    try {
      this.XMLHttp = new XMLHttpRequest();
    } catch (ex) {
      if (debug) errorMsg("error creating direct obj", ex);
    };
  } else if (window.ActiveXObject) {
    //For MS browsers
    var prefix = getHttpControlPrefix(this.debug);
    if (prefix != null) {
      try {
        this.XMLHttp = new ActiveXObject(prefix + msieXmlHttpSuffix);
      } catch (ex) {
        if (debug) alert(errorMsg("error creating msie obj " + prefix, ex));
      };
    } else {
      if (debug) alert("http control prefix not found for msie");
    }
  }
  if (!this.XMLHttp && debug) alert("can't create http control");
}

HttpClient.prototype.isSupported = function(method) {
  return this.XMLHttp
}

HttpClient.prototype.executeMethod = function(method) {
  // this copy has to be made in order to keep the closure open
  var mXMLHttp = this.XMLHttp;
  if (this.XMLHttp) {
    var url = method.url;
    var methodType;
    if (method instanceof GetMethod) {
      methodType = "GET";
    } else {
      methodType = "POST";
    }

    this.XMLHttp.open(methodType, url, !method.sync);
    this.XMLHttp.onreadystatechange = function() {
      if (this.debug) alert("readyState = " + mXMLHttp.readyState);
      if (mXMLHttp.readyState == 4 && !method.sync) {
        // hit the callback function if the request is complete and the status is OK
        if (mXMLHttp.status == 200) {
          method.successCallback(mXMLHttp);
        } else {
        // hit the failure function if the request is complete and the status is not OK
          method.failureCallback(mXMLHttp);
        }
      }
    }
    if (method.dat != null) {
      this.XMLHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }
    if (this.debug) alert("about to send sync=" + method.sync + " method="+methodType+" to url="+url+" with data="+method.dat);
    this.XMLHttp.send(method.dat)
    
    // if sync, then onreadystatechange isn't called, so call
    // the appropriate callback ourselves.
    if (method.sync) {
      if (mXMLHttp.status == 200) {
        method.successCallback(mXMLHttp);
      } else {
        method.failureCallback(mXMLHttp);
      }
    }
    
    return 1;
  }
  return 0;
}

/**
 * An aynchronous GET operation
 * 
 * @param url The target Url for this HTTP request
 * @param successCallback (optional) An optional success callback method which takes 1 parameter, the XMLHttpRequest object
 * @param failureCallback (optional) An optional failure callback method which takes 1 parameter, the XMLHttpRequest object
 */
function GetMethod(url, successCallback, failureCallback) {
  this.url = url;
  this.successCallback = (successCallback != null ? successCallback : noop);
  this.failureCallback = (failureCallback != null ? failureCallback : noop);
  this.dat = null;
  this.sync = false;
}

/**
 * An synchronous GET operation
 * 
 * @param url The target Url for this HTTP request
 * @param successCallback (optional) An optional success callback method which takes 1 parameter, the XMLHttpRequest object
 * @param failureCallback (optional) An optional failure callback method which takes 1 parameter, the XMLHttpRequest object
 */
function GetMethodSync(url, successCallback, failureCallback) {
  this.url = url;
  this.successCallback = (successCallback != null ? successCallback : noop);
  this.failureCallback = (failureCallback != null ? failureCallback : noop);
  this.dat = null;
  this.sync = true;
}


/**
 * An aynchronous POST operation
 * 
 * @param url The target Url for this HTTP request
 * @param successCallback (optional) An optional success callback method which takes 1 parameter, the XMLHttpRequest object
 * @param failureCallback (optional) An optional failure callback method which takes 1 parameter, the XMLHttpRequest object
 * @param dat Data to post
 */
function PostMethod(url, successCallback, failureCallback, dat) {
  this.url = url;
  this.successCallback = (successCallback != null ? successCallback : noop);
  this.failureCallback = (failureCallback != null ? failureCallback : noop);
  this.dat = dat;
  this.sync = false;
}

/**
 * A synchronous POST operation
 * 
 * @param url The target Url for this HTTP request
 * @param successCallback (optional) An optional success callback method which takes 1 parameter, the XMLHttpRequest object
 * @param failureCallback (optional) An optional failure callback method which takes 1 parameter, the XMLHttpRequest object
 * @param dat Data to post
 */
function PostMethodSync(url, successCallback, failureCallback, dat) {
  this.url = url;
  this.successCallback = (successCallback != null ? successCallback : noop);
  this.failureCallback = (failureCallback != null ? failureCallback : noop);
  this.dat = dat;
  this.sync = true;
}

function noop() {};

function postDataFromForm(form) {
  var dat = "";
  for (var i = 0; i<form.elements.length; i++) {
  	var fieldStr = getURIEncodedFieldValue(form.elements[i]);
    dat += fieldStr;
  }
  
  if (debug) {
    alert("Post Data = " +dat);
  }
  
  return dat;
}

/*
 * This function will return a URL encoded representation of a field . The 
 * function will typically return '&[fieldname]=[value]' unless the field is 
 * a radio button in which case it will only return an encoded string if the value
 * is checked.
 */
function getURIEncodedFieldValue(field) {
	var val = getFieldValue(field);
	var result = "";
	if (field.type != "radio" || field.checked){
	    result += "&" + field.name + "=" + encodeURIComponent(val);
	}
	return result;
}

// borrowed from struts validateRequired static js function
// get the value of a form field
function getFieldValue(field) {
  if (field.disabled == true)
    return null;
  if (field.type == 'hidden' ||
      field.type == 'text' ||
      field.type == 'textarea' ||
      field.type == 'file' ||
      field.type == 'checkbox' ||
      field.type == 'select-one' ||
      field.type == 'password' ||
      field.type == 'radio') {
    var value = '';
    // get field's value
    if (field.type == "select-one") {
      var si = field.selectedIndex;
      if (si >= 0) {
        value = field.options[si].value;
      }
    } else if (field.type == 'checkbox' || field.type == 'radio') {
      if (field.checked) {
        value = field.value;
      }
    } else {
      value = field.value;
    }
  } else if (field.type == "select-multiple") { 
    var numOptions = field.options.length;
    for(loop=numOptions-1;loop>=0;loop--) {
      if (field.options[loop].selected) {
        if (value.length > 0)
          value += ",";
        value += field.options[loop].value;
      }
    }
  }
  return value;
}


