/* AjaxRequest.js */

/**
 * @class    AjaxRequest
 * @param    string $requestMethod : one of "POST" or "GET", defaults to null
 * @param    string $requestUri : the URI requested, defaults to null
 * @param    object $requestParameters : parameters to be sent to server (i.e. user_id=12345) as name:value pairs, defaults to empty object
 * @param    object $requestHeaders : HTTP headers to be sent to server as name:value pairs, defaults to empty object
 * @returns  void
 */

function AjaxRequest( $requestMethod, $requestUri, $requestParameters, $requestHeaders )
{
  /**
   * @private  $_self
   * @type     object : self-referencing for scope resolution
   */
   
  var $_self = this;
  
  
  /**
   * @private  requestMethod
   * @type     string : one of "POST" or "GET", null until set
   */
  
  var requestMethod = ( $requestMethod ) ? $requestMethod.toUpperCase() : null;
  
  
  /**
   * @private  requestUri
   * @type     string : the URI we're requesting, null until set
   */
  
  var requestUri = $requestUri || null;
  
  
  /**
   * @private  requestParameters
   * @type     object : parameters sent to server, empty object until set
   */
  
  var requestParameters = $requestParameters || new Object();
  
  
  /**
   * @private  requestHeaders
   * @type     object : HTTP headers, empty object until set
   */
  
  var requestHeaders = $requestHeaders || new Object();
  
  
  /**
   * @private  asynchronous
   * @type    boolean : whether or not the request is made asynchronously, defaults to true
   */
  
  var asynchronous = true;
  
  
  /**
   * @private  request
   * @type     object : XMLHttpRequest instance / the whole reason we're here ;)
   */
  
  var request = getRequest();
  
  
  /**
   * @public   setRequestMethod
   * @param    string $requestMethod : one of "POST" or "GET", the script will fail on AjaxRequest.Send() if otherwise
   * @returns  void
   */
  
  this.setRequestMethod = function( $requestMethod )
  {
    requestMethod = $requestMethod.toUpperCase();
    
    return;
    
  }; // this.setRequestMethod()
  
  
  /**
   * @public   getRequestMethod
   * @returns  string requestMethod
   */
  
  this.getRequestMethod = function()
  {
    return requestMethod;
    
  }; // this.getRequestMethod()
  
  
  /**
   * @public   setRequestUri
   * @param    string $requestUri : the uri we're posting to/getting
   * @returns  void
   */
  
  this.setRequestUri = function( $requestUri )
  {
    requestUri = $requestUri;
    
    return;
    
  }; // this.setRequestUri()
  
  
  /**
   * @public   getRequestUri
   * @returns  string requestUri
   */
  
  this.getRequestUri = function()
  {
    return requestUri;
    
  }; // this.getRequestUri()
  
  
  /**
   * @public   setRequestParameter
   * @param    string $parameter : i.e. "user_id"
   * @param    string $value : i.e. "12345"
   * @returns  void
   */
  
  this.setRequestParameter = function( $parameter, $value )
  {
    requestParameters[$parameter] = $value;
    
    return;
    
  }; // this.setRequestParameter()
  
  
  /**
   * @public   getRequestParameter
   * @param    string $parameter : i.e. "user_id"
   * @returns  mixed if value found for $parameter, false on failure
   */
  
  this.getRequestParameter = function( $parameter )
  {
    try
    {
      return requestParameters[$parameter];
    }
    catch( exception )
    {
      return false;
    }
    
  }; // this.getRequestParameter()
  
  
  /**
   * @public   setRequestParameters
   * @param    object $parameters : parameters sent to the server
   * @returns  void
   */
  
  this.setRequestParameters = function( $parameters )
  {
    requestParameters = $parameters || new Object();
    
    return;
    
  }; // this.setRequestParameters()
  
  
  /**
   * @public   getRequestParameters
   * @returns  object
   */
  
  this.getRequestParameters = function()
  {
    return requestParameters;
    
  }; // this.getRequestParameters()
  
  
  /**
   * @public   setRequestHeader
   * @param    string $httpEquiv
   * @param    string $content
   * @returns  void
   */
  
  this.setRequestHeader = function( $httpEquiv, $content )
  {
    requestHeaders[$httpEquiv] = $content;
    
    return;
    
  }; // this.setRequestHeader()
  
  
  /**
   * @public   getRequestHeader
   * @param    $httpEquiv
   * @returns  mixed on success, false on failure
   */
  
  this.getRequestHeader = function( $httpEquiv )
  {
    try
    {
      return requestHeaders[$httpEquiv];
    }
    catch( error )
    {
      try
      {
        return request.getRequestHeader( $httpEquiv );
      }
      catch( error )
      {
        return false;
      }
    }
    
  }; // this.getRequestHeader()
  
  
  /**
   * @public   setRequestHeaders
   * @param    $requestHeaders
   * @returns  void
   */
  
  this.setRequestHeaders = function( $requestHeaders )
  {
    requestHeaders = $requestHeaders;
    
    return;
    
  } // this.setRequestHeaders()
  
  
  /**
   * @public   asynchronous
   * @param    boolean $setting
   * @returns  void
   */
  
  this.asynchronous = function( $setting )
  {
    if( $setting )
    {
      asynchronous = true;
    }
    else
    {
      asynchronous = false;
    }
    
    return;
    
  }; // this.asynchronous()
  
  
  /**
   * @public  send
   * @returns void
   */
  
  this.send = function()
  {
    var queryString = requestParametersToString();
    
    if( requestMethod == "POST" )
    {
      // set appropriate headers
      this.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
      this.setRequestHeader( 'Content-Length', queryString.length );
      this.setRequestHeader( 'Connection', 'close' );
      
      // open the connection and send headers
      open();
      
      // send the request with the params
      request.send( queryString );
    }
    else if( requestMethod == "GET" )
    {
      $oldUri = requestUri;
      
      // add params to uri
      requestUri += "?" + queryString;
      
      // open the connection and send headers
      open();
      
      // send the request
      request.send( null );
      
      requestUri = $oldUri;
    }
    else
    {
      // in case we fuck up
      throw "AjaxRequest.requestMethod may only be one of \"POST\" or \"GET\", \"' + requestMethod + '\" given.";
    }
    
    return;
    
  }; // this.send()
  
  
  /**
   * @public   readyStateChange
   * @param    callback $function
   * @returns  void
   */
  
  this.readyStateChange = function( $function )
  {
    request.onreadystatechange = function()
    {
      // execute a callback function
      $function( request );
    }
    
    return;
    
  } // this.onReadyStateChange()
  
  
  /**
   * @private  getRequest
   * @returns  object XMLHttpRequest or ActiveXObject
   * @throws   Error
   */
  
  function getRequest()
  {
    try 
    { 
      return new ActiveXObject( "Msxml2.XMLHTTP.6.0" ); 
    }
    catch( error )
    {
      try 
      { 
        return new ActiveXObject( "Msxml2.XMLHTTP.3.0"); 
      } 
      catch( error )
      {
        try 
        { 
          return new ActiveXObject( "Msxml2.XMLHTTP" ); 
        } 
        catch( error )
        {
          try 
          { 
            return new ActiveXObject( "Microsoft.XMLHTTP" ); 
          } 
          catch( error )
          {
            try 
            { 
              return new XMLHttpRequest(); 
            } 
            catch( error )
            {
              throw new Error( "Browser does not support XMLHttpRequest" );
              
              return false;
            }
          }
        }
      }
    }
    
  }; // getRequest()
  
  
  /**
   * @private  requestParametersToString
   * @returns  string : query string to be sent to server
   */
  
  function requestParametersToString()
  {
    var paramsArray = new Array();
    var index = 0;
    
    for( var param in requestParameters )
    {
      paramsArray[index] = param + "=" + requestParameters[param];
      index = index + 1;
    }
    
    return paramsArray.join( "&" );
    
  } // requestParametersToString()
  
  
  /**
   * @private  open
   * @returns  void
   */
  
  function open()
  {
    // open request to server
    request.open( requestMethod, requestUri, asynchronous );
    
    for( var httpEquiv in requestHeaders )
    {
      // send headers
      request.setRequestHeader( httpEquiv, requestHeaders[httpEquiv] );
    }
    
    // reset @property requestHeaders to empty object
    this.requestHeaders = new Object();
    
    return;
    
  } // open()
  
} // AjaxRequest()
