
/**
 *
 * Ajax()
 *
 * constructor()
 *
 * Ajax Core Library
 *
 * @author     Matt Wild 11/2008
 *
 * @todo add more debugging
 * @todo change header to request header as well as add response header
 *
 */
function AjaxSS()
{
   /*
    * @var    xmlHttpReq
    * @usage  core XML DOM Object
    * @access private
    */
   this.xmlHttpReq = false;

   /*
    * @var    url
    * @usage  path to post: index.php
    * @access private
    */
   this.url = '';

   /*
    * @var    header
    * @usage  headers sent during request
    * @access private
    */
   this.header = new Object();

   this.header['Accept-Charset']            = '';
   this.header['Accept-Encoding']           = '';
   this.header['Connection']                = '';
   this.header['Content-Length']            = '';
   this.header['Content-Type']              = 'application/x-www-form-urlencoded';
   this.header['Host']                      = '';
   this.header['Content-Transfer-Encoding'] = '';
   this.header['Date']                      = '';
   this.header['Expect']                    = '';
   this.header['Host']                      = '';
   this.header['Keep-Alive']                = '';
   this.header['Referer']                   = '';
   this.header['TE']                        = '';
   this.header['Trailer']                   = '';
   this.header['Transfer-Encoding']         = '';
   this.header['Upgrade']                   = '';
   this.header['Via']                       = '';
   this.header['Man']                       = '';
   this.header['MessageType']               = '';

   /*
    * @var    serializedHeader
    * @usage
    * @access private
    */
   this.serializedHeader = '';

   /*
    * @var    params
    * @usage  POST or GET parameters in object form
    * @access private
    */
   this.params = '';

   /*
    * @var    serializedParams
    * @usage  POST or GET parameters: var1=param1&var2=param2
    * @access private
    */
   this.serializedParams = '';

   /*
    * @var    method
    * @usage  defines post method POST or GET
    * @access private
    *
    * @todo add SOAP param
    */
   this.method = 'POST';

   /*
    * @var    callBack
    * @usage  function to give the request reponse
    * @access private
    */
   this.callBack = '';

   /*
    * @var    resultId
    * @usage  element id which the reponse is sent to
    * @access private
    */
   this.resultId = '';

   /*
    * @var    async
    * @usage
    * @access private
    */
   this.async = 1;

   /*
    * @var    responseType
    * @usage  expected format of response XML or TEXT
    * @access private
    */
   this.responseType = '';

   /*
    * @var    debugContainer
    * @usage
    * @access private
    */
   this.debugContainer = 'debugContainer';

   /*
    * @var    debugFlag
    * @usage
    * @access private
    */
   this.debugFlag = 0;

   /*
    * @var    args
    * @usage
    * @access private
    */
   this.args = new Object();
}

/**
 * Debug()
 *
 * @param string what
 *
 */
AjaxSS.prototype.Debug = function(what)
{
   if(this.debugFlag >= 1)
   {
      //Make sure its not junk
      //
      if(typeof(what) == 'string')
      {
         if(what.length > 0)
         {
            if(window.document.getElementById(this.debugContainer))
            {
               var time = new Date();

               element = window.document.getElementById(this.debugContainer);

               element.innerHTML += '<br/>' + time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds() + '  ' + what;
               element.scrollTop  = element.scrollHeight;
            }
         }
      }
   }
}

/**
 *
 * InitBrowser()
 *
 *
 * Method prepares initial browser support
 *
 * @static
 * @access private
*/
AjaxSS.prototype.InitBrowser = function()
{
   var BrowserSupported = true;

   //Browser support
   //
   if(window.ActiveXObject)
   {
      //Attempt to assign based on legacy or new IE
      //
      try
      {
         this.xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
      }
      catch(e)
      {
         this.Debug(e);

         try
         {
            this.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
         }
         catch(e)
         {
            this.Debug(e);

            BrowserSupported = false;
         }
      }
   }
   else if(window.XMLHttpRequest)
   {
      try
      {
         this.xmlHttpReq = new XMLHttpRequest();
      }
      catch(e)
      {
         this.Debug(e);

         BrowserSupported = false;
      }
   }
   else
   {
      BrowserSupported = false;
   }

   return BrowserSupported;
}

/**
 *
 * BuildParameters()
 *
 * @static
 * @access private
*/
AjaxSS.prototype.BuildParameters = function()
{
   if(typeof(this.params) == 'string')
   {
      this.serializedParams = this.params;
   }
   else if(typeof(this.params) == 'object')
   {
      var firstPass = true;

      //Foreach parameter, build a string
      //
      for(key in this.params)
      {
         if(firstPass)
         {
            firstPass = false;

            this.serializedParams = key + '=' + escape(this.params[key]);
         }
         else
         {
            this.serializedParams = this.serializedParams + '&' + key + '=' + escape(this.params[key]);
         }
      }
   }
   else
   {
      this.serializedParams = '';
   }

   this.Debug(this.serializedParams);
}

/**
 * Context()
 *
 * Initializes an XMLHTTP request, and specifies the method, URL, and authentication information for the request.
 *
 * If open is called with async == False, this call does not return until
 * the entire response is received or the protocol stack times out. If open
 * is called with async == True, this call returns immediately
 *
 * @access private
 * @throws exception
 */
AjaxSS.prototype.Context = function()
{
   try
   {
      this.Debug('Opening Stream in Function: Context()');
      this.Debug(this.method);
      this.Debug(this.url);
      this.Debug(this.async);

      //netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

      this.xmlHttpReq.open(this.method, this.url, this.async);
   }
   catch(e)
   {
      throw(e);
   }
}

/**
 * BuildHeaders()
 *
 * @access private
 * @throws exception
 */
AjaxSS.prototype.BuildHeaders = function()
{
   this.Debug('Building Headers');

   //Foreach parameter, build a string
   //
   for(key in this.header)
   {
      try
      {
         this.Debug(key + ':   ' + this.header[key]);

         this.xmlHttpReq.setRequestHeader(key, this.header[key]);
      }
      catch(e)
      {
         this.Debug(e);

         throw(e);
      }
   }
}

/**
 * Call()
 *
 * Method makes all requests and handles response direction
 *
 *
 * @static
 * @access private
 * @todo automatic identification of response type via headers
 * @todo return an object to the callback function - grant access to certain things
 *
*/
AjaxSS.prototype.Call = function()
{
   //Open the Stream
   //
   try
   {
      this.Context();
   }
   catch(e)
   {
      this.Debug(e);

      throw(e)
   }

   //Serialize the headers
   //
   try
   {
      this.BuildHeaders();
   }
   catch(e)
   {
      this.Debug(e);

      throw(e)
   }

   //Serialize the Parameters
   //
   try
   {
      this.BuildParameters();
   }
   catch(e)
   {
      this.Debug(e);

      throw(e)
   }

   //Necessary for scope within anonymous function: onreadystatechange()
   //
   contextStream = this;

   contextStream.xmlHttpReq.onreadystatechange = function()
   {
      if(contextStream.async)
      {
         contextStream.Debug('readyState ' + contextStream.xmlHttpReq.readyState);

         /**
          * 0 (uninitialized)
          * 1 (loading)
          * 2 (loaded)
          * 3 (interactive)
          * 4 (complete)
          *
          */
         switch(contextStream.xmlHttpReq.readyState)
         {
            case 0:
               break;
            case 1:
               break;
            case 2:
               break;
            case 3:
               break;
            case 4:

               switch(contextStream.responseType)
               {
                  case 'XML':
                     contextStream.Debug(contextStream.xmlHttpReq.responseXML);

                     contextStream.callBack(contextStream.xmlHttpReq.responseXML);
                     break;

                  case 'TEXT':
                     contextStream.Debug(contextStream.xmlHttpReq.responseText);

                     contextStream.callBack(contextStream.xmlHttpReq.responseText);
                     break;

                  default:
                     contextStream.callBack('ERROR: undefined response type');

                     throw('ERROR: undefined response type');
               }

               break;
         }
      }
   }

   //Attempt the Request
   //
   try
   {
      contextStream.xmlHttpReq.send(this.serializedParams);

      if(! contextStream.async)
      {
         switch(contextStream.xmlHttpReq.status)
         {
            case 200:

               this.Debug('HTTP Status:     ' + contextStream.xmlHttpReq.status);
               this.Debug('HTTP StatusText: ' + contextStream.xmlHttpReq.statusText);

               switch(contextStream.responseType)
               {
                  case 'XML':
                     contextStream.Debug(contextStream.xmlHttpReq.responseXML);

                     contextStream.callBack(contextStream.xmlHttpReq.responseXML);
                     break;

                  case 'TEXT':
                     contextStream.Debug(contextStream.xmlHttpReq.responseText);

                     contextStream.callBack(contextStream.xmlHttpReq.responseText);
                     break;

                  default:
                     contextStream.callBack('ERROR: undefined response type');

                     throw('ERROR: undefined response type');
               }

               break;

            case 404:

               this.Debug('HTTP Status:     ' + contextStream.xmlHttpReq.status);
               this.Debug('HTTP StatusText: ' + contextStream.xmlHttpReq.statusText);

               break;
         }
      }
   }
   catch(e)
   {
      this.Debug(e);

      throw(e)
   }
}

/**
 * Request()
 *
 * Encapsulates Ajax calls and validates credentials
 *
 * @param string     inUrl
 * @param function   inCallBack
 * @param object     inParams
 * @param string     inResponseType
 *
 * @throws exception
 *
 * @todo encode url
 * @todo eliminate number of params by allowing mixed
 *
 */
function Request(inUrl, inCallBack, inParams, inDebug, inAsync, inResponseType, inDebugContainer)
{
   postAjax = new AjaxSS();

   //First ensure environment initialization
   //
   if(! postAjax.InitBrowser())
   {
      throw('Browser not supported');
   }

   //Check URL - The URL is the only requirement
   //
   if(typeof(inUrl) == 'string')
   {
      if(inUrl.length > 0)
      {
         postAjax.url = inUrl;
      }
      else
      {
         throw('Missing URL input');
      }
   }
   else
   {
      throw('Invalid URL type input');
   }

   //Check Call Back
   //
   if(typeof(inCallBack) == 'function')
   {
      postAjax.callBack = inCallBack;
   }
   else
   {
      throw('Invalid Call Back type input');
   }

   postAjax.params = inParams;

   //Asynchronous
   //
   if(typeof(inAsync) != 'undefined' & typeof(inAsync) != 'null')
   {
      postAjax.Debug('Setting inAsync: ' + inAsync);
      postAjax.async = inAsync;
   }
   else
   {
      postAjax.Debug('inAsync: ' + postAjax.async);
   }

   //Turn on off debugging
   //
   if(inDebug)
   {
      postAjax.debugFlag = 1;
   }

   //Optional debug container
   //
   if(typeof(inDebugContainer) == 'string')
   {
      if(inDebugContainer.length > 0)
      {
         postAjax.debugContainer = inDebugContainer;
      }
   }

   //Check responseType
   //
   if(typeof(inResponseType) == 'string')
   {
      if(inResponseType.length > 0)
      {
         switch(inResponseType.toLowerCase())
         {
            case 'xml':

               postAjax.responseType = 'XML';

               break;

            case 'text':

               postAjax.responseType = 'TEXT';

               break;

            default:
               postAjax.responseType = 'TEXT';
         }
      }
      else
      {
         postAjax.responseType = 'TEXT';
      }
   }
   else
   {
      postAjax.responseType = 'TEXT';
   }

   try
   {
      postAjax.Call();
   }
   catch(e)
   {
      throw(e);
   }
}