/**
 * clacks_1.js
 *
 * @copyright: 2009 by Thomas M. Stambaugh & Zeetix, LLC (http://www.zeetix.com)
 * All rights reserved.
 *
 * The contents of this file may not be copied, duplicated, or used without the
 * written consent of Zeetix, LLC.
 *
 * Ajax handling from "Ajax Hacks by Bruce Perry. Copyright 2006 O'Reilly Media, Inc., 0-596-10169-4.".
 *
 * Separate into HttpRequest (for GET requests) and HttpPostRequest (for POST
 * requests).
**/

/**
 *  Each instance of HttpRequest handles a single browser/server
 *  interaction.
**/
function HttpRequest(){};
HttpRequest.prototype = new Object();
HttpRequest.prototype.constructor = HttpRequest;
HttpRequest._superclass = Object.prototype;

/**
 * Creates and answers a new instance.
 *
 *    reqType: The HTTP request type, such as GET or POST. This is determined
 *      from the class of the receiver.
 *    aUrl: The URL of the server program.
 *    isAsynch: Whether to send the request asynchronously or not.
 *    aRespHandler: The name of the function that will handle the response.
 *    aPostData: QueryString-formatted postData
**/
HttpRequest.createUrl_isAsynch_responseHandler_ = function (aUrl, isAsynch, aResponseHandler) {
  var answer = new HttpRequest();
  answer.initializeWithUrl_isAsynch_responseHandler_(aUrl, isAsynch, aResponseHandler);
  return answer;
};

HttpRequest.prototype.initializeWithUrl_isAsynch_responseHandler_ = function (aUrl, isAsynch, aResponseHandler) {
  this._url = aUrl;
  this._isAsynch = isAsynch;
  this._responseHandler = aResponseHandler;
  this._request = this.xmlHttpRequestPreset();
};

/**
 * Creates and answers an xmlHttpRequest object for the receiver.
 *
 */
HttpRequest.prototype.xmlHttpRequestPreset = function() {
  var answer;
  //Mozilla-based browsers
  if(window.XMLHttpRequest){
    answer = new XMLHttpRequest(  );
    }
  else if (window.ActiveXObject){
    answer=new ActiveXObject("Msxml2.XMLHTTP");
    if (! answer){
      answer=new ActiveXObject("Microsoft.XMLHTTP");
      }
    }

  //very unlikely, but we test for a null request
  //if neither ActiveXObject was initialized
  if(!answer) {
    alert("Your browser does not permit the use of all "+
        "of this application's features!");
    }
  return answer;
};

/**
 * Hook methods
 *
 * Descendants override these to specialize the AJAX protocol.
**/

/**
 * HttpRequest uses GET.
**/
HttpRequest.prototype.doOpen = function() {
  this._request.open('GET', this._url, this._isAsynch);
};

/**
 * HttpRequest always sends null.
**/
HttpRequest.prototype.doSend = function() {
  this._request.send(null);
};

/**
 * HttpRequest does nothing.
**/
HttpRequest.prototype.doSetRequestHeader = function() {
};

/**
 * Protocol methods
**/

HttpRequest.prototype.getCallback = function () {
  var anHttpRequest = this;
  var answer = function () {
    /**
     * This closure uses anHttpRequest to capture the receiver of the wrapper.
     * "this" is bound to the platform request object (XMLHttpRequest in Firefox)
     * active when it runs.
    **/
    if(this.readyState == 4){
      if(this.status == 200){
        anHttpRequest._responseText = this.responseText;
        anHttpRequest._responseHandler(anHttpRequest);
        }
      else {
        alert(
          "Status code: " + this.status.toString()
          + "Status text: " + this.statusText
          );
        }
      }
    };
  return answer;
};

/**
 * On a successful response, collects the data from
 * the XmlHttpRequest. Then invoke the callback closure
 * of the receiver with the (updated) receiver as its single
 * argument.
 *
 * Each callback should be a closure that invokes an arbitrary
 * method on an arbitrary listener with the receiver as its argument.
 */
HttpRequest.prototype.armCallbacks = function () {
  var anHttpRequest = this;
  this._request.onreadystatechange = function () {
    /**
     * This closure uses anHttpRequest to capture the receiver of the wrapper.
     * "this" is bound to the platform request object (XMLHttpRequest in Firefox)
     * active when it runs.
    **/
    if(this.readyState == 4){
      if(this.status == 200){
        anHttpRequest._responseText = this.responseText;
        anHttpRequest._responseHandler(anHttpRequest);
        }
      else {
        //anHttpRequest._exceptionHandler(anHttpRequest)
        alert(
          "Status code: " + this.status.toString()
          + "Status text: " + this.statusText
          );
        }
      }
    };
  };

HttpRequest.prototype.open = function () {
  this.doOpen();
};

HttpRequest.prototype.setRequestHeader = function() {
  this.doSetRequestHeader();
};

HttpRequest.prototype.send = function() {
  this.doSend();
};

/**
 * Interface methods
 */

/**
 * Submits the supplied postData to the server and answers the response.
 *
 * Should this check for and block if the receiver is already active?
 */
HttpRequest.prototype.submit_ = function(aPostData) {
  this._postData = aPostData;
  this.run();
};

/**
 * Fire the xmlHttpRequest of the receiver, snarfing arguments
 * from the receiver as needed.
 *
 * Capture the responseText from the receiver's request, then
 * invoke the responseHandler with the receiver as its single argument.
 *
 * Uses anHttpRequest in the outer closure to pass the wrapper into the the
 * inner closure, so that it can be passed to the responseHandler.
 */
HttpRequest.prototype.run = function() {
  /* Make myself active */
  this.armCallbacks();
  this.open();
  this.setRequestHeader();
  this.send();
};

/**
 * Use HttpPostRequest for POST requests.
**/
function HttpPostRequest(){};
HttpPostRequest.prototype = new HttpRequest();
HttpPostRequest.prototype.constructor = HttpPostRequest;
HttpPostRequest._superclass= HttpRequest.prototype;

/**
 * Creates and answers a new instance.
 *
 *    reqType: The HTTP request type, such as GET or POST. This is determined
 *      from the class of the receiver.
 *    aUrl: The URL of the server program.
 *    isAsynch: Whether to send the request asynchronously or not.
 *    aRespHandler: The name of the function that will handle the response.
 *    aPostData: QueryString-formatted postData
**/
HttpPostRequest.createUrl_isAsynch_responseHandler_postData_ = function (aUrl, isAsynch, aResponseHandler, aPostData) {
  var answer = new HttpPostRequest();
  answer.initializeWithUrl_isAsynch_responseHandler_postData_(aUrl, isAsynch, aResponseHandler, aPostData);
  return answer;
};

HttpPostRequest.prototype.initializeWithUrl_isAsynch_responseHandler_postData_ = function (aUrl, isAsynch, aResponseHandler, aPostData) {
  this.initializeWithUrl_isAsynch_responseHandler_(aUrl, isAsynch, aResponseHandler);
  this._postData = aPostData
};

/**
 * Hook methods
 *
 * Descendants override these to specialize the AJAX protocol.
**/

/**
 * HttpPostRequest uses Post.
**/
HttpPostRequest.prototype.doOpen = function() {
  this._request.open('POST', this._url, this._isAsynch);
};

/**
 * HttpPostRequest sends its postData.
**/
HttpPostRequest.prototype.doSend = function() {
  this._request.send(this._postData);
};

/**
 * HttpPostRequest sets the content-type.
**/
HttpPostRequest.prototype.doSetRequestHeader = function() {
  if (this._postData) {
    this._request.setRequestHeader("Content-Type",
      "application/x-www-form-urlencoded; charset=UTF-8");
    }
};
