// Requires json2.js
  
  // 2008.02.07
  // Clients may be allowed only two connections to a host at a time.
  // Hosts may be tuned to many quick requests (rather than a few long connections)
  //
  // Currently works Kinda like email... where you queue up messages to send.. 
  // then process messages by sending what you have and get messages waiting.
  // 
  
  // All messages, both snd/rcv use the one xmlhttpreq corrirer.
  
  // (support two channels?)

  var comAgentList = [];//for async message references (what other way can we accomplish this?)
  var comAgentServiceList = {};//for async message references (what other way can we accomplish this?)
  
  //var defaultComAgent = new comAgent();
  var comAgentDefaultAgent;//will be set below 

  //comAgent object 
  function comAgent(server_url)
  {
  comAgentList.push(this);
  this.index = comAgentList.length-1;
  
   if(!server_url)
     server_url = root_path+"/squax-server.php";
     
   this.serverURL = server_url
   //this.readyXHR(); //still getting errors.. move this to on send 2008.05.08

   // this.send('comAgent','hello',true);  REM FOR HACK [2008.04.11] -- see if effects the IE bug
   //this.tick();  -- REM FOR HACK [2008.04.11] -- see if effects the IE bug 
  }//func

  comAgent.prototype.notify = false; // event function to call
  comAgent.prototype.mailCall = false; // event function to call just before sending mail
  comAgent.prototype.outbox = [];
//  comAgent.prototype.inbox = [];
  comAgent.prototype.XHR = false; //xhrAgent
  comAgent.prototype.serverURL = false;
  comAgent.prototype.transaction = false;//start out "transacting" the creation of the agent (don't start out 2008.05.08 - include when we make a call)
  comAgent.prototype.lastCheck = 0;
  comAgent.prototype.nextReviewSituationDelay = 3000;
  comAgent.prototype.agentID = false
  comAgent.prototype.processAgain = false; // NEED TO Add SUPPORT FOR THIS: so we send right when we're done because we asked for a send while we were away.

  comAgent.prototype.MAX_SEND_WAIT = 3500;
  comAgent.prototype.MAX_CHECK_WAIT = 300000;
  

  
  
  function comAgentDefault()
  {
  return comAgentDefaultAgent;
  }
  
  function comAgentAddService(n)
  {  
    return comAgentDefault().addService(n);
  }//func
  
  
  function comAgentPostMessage(service,msg)
  {
  
  var result = false;

  //make sure this service has been registered  
   var a = comAgentSureService(service);
  
   result = a.postMessage(msg);
  
  return result;
  }


  function comAgentMessageReadyCall(service,func)
  {
   var a = comAgentSureService(service);
   
   a.messageReadyCall(func);
   
  }//func  


  function comAgentProcessMessages()
  {
  comAgentDefault().processMessages();
  }

/////////////////////////////////////////////////////////////////
  
  function comAgentSureService(serviceName)
  {
    var a = comAgentServiceList[serviceName];
    
    if(!a)
    {
    console.log('Auto Creating a service '+serviceName)
    a = comAgentAddService(serviceName);
    }//if


   return a;
  }//func
    
  
// ********************************************************** //
  
  comAgent.prototype.addService =
    function (service_name)
    {
    //create and return a service helper object
    var s = new comAgentService(service_name);
    s.comAgent = this;
    
    console.log('new service: '+service_name)
    console.log(comAgentServiceList);
    return s;
    }//func
  
// ********************************************************** //  
  comAgent.prototype.send =   
  function(service_name,msg,send_now) //max wait time in ms
    {//user send msg
    this.outbox.push([service_name,msg]);
    
    
    if((send_now))
      this.processMessages();
    }
    
// ********************************************************** //    
    
  //comAgent.prototype.recv =  
  //function ()
  //  {//user call read next msg in inbox (delete message from inbox on read)
  //    //return this.inbox.shift();
  //  }
    
// ********************************************************** //  
    
  //comAgent.prototype.inboxLen =
  //function ()
  //  {//user number of messages waiting in local inbox 
    //return this.inbox.length;
  //  }
    
  
  
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////  
  
  comAgent.prototype.isTransacting =
  function ()
  {
  //return (comXHR.readyState == 0)
  return this.transaction;
  }
  
  
// ********************************************************** //  
  

  comAgent.prototype.readyXHR =
  function ()
  {//will go crazy if create new ready while away
    var fstr = "comAgentList["+this.index+"].XHREvent()";
    
    console.log('making a new XHR');
    console.log(fstr);
    
    //dispose any old XHR
    if(this.XHR)
      delete this.XHR;
      
     //ready but do not yet send anything
     this.XHR = this.newXMLHttpReqObj(); //make sure we're ready
     this.XHR.open('POST',this.serverURL,true);
     
     this.XHR.onreadystatechange = //this.XHREvent;//function name
       new Function("",fstr);
          
     this.XHR.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
     
     this.transaction = false;
     console.log('Readied XHR');
  }
  
  
   
// ********************************************************** //   
  comAgent.prototype.processMessages = 
  function ()
    {//fails if away
    var group = [];
    
    
    console.log('processMessages');
    
    if(!this.isTransacting())
      {
      
      this.readyXHR();//make sure we have a XHR
      
      this.transaction = true;
      
      var o = "";
      var msg;    
      
      //one last chance to add messages
      if(this.mailCall)
        this.mailCall();
      
      
      while(this.outbox.length > 0)
        {
        group.push(this.outbox.shift());
        }//while
        
      o = JSON.stringify([this.agentID,group]);
      
  
      console.log(o);
      o = "p="+encodeURIComponent(o);
      console.log(o);
      
      this.XHR.send(o);//send our messages away.. and receive any new messages
      
      return true;
      }
    else
      {
        console.log('request to process.. when we are in processing.')
        if(this.outbox.length > 0)
          {
          console.log('que to start right away')
          console.log(this.outbox)
          this.processAgain = true;
          }
        
      return false;
      }
      
    }//func
  
// ********************************************************** //
  
  comAgent.prototype.XHREvent = 
  function ()
  {
  var s = this.XHR.readyState;
  var o = null;
  var i;
  var msg;
  var srv_name;
  var new_message_service_list = {}
  //console.log(" s:"+s+" ")
  
  //0 = uninitialized - open() has not yet been called. 
  //1 = open - send() has not yet been called. 
  //2 = sent - send() has been called, headers and status are available. 
  //3 = receiving - Downloading, responseText holds partial data (although this functionality is not available in IE [3]) 
  //4 = loaded - Finished. 
  
  if(s == 4)
      {
      var r = this.XHR.responseText;
      var d = new Date();
      
      this.lastCheck = d.getTime();
      
      console.log("Response IS! = "+r+"")
      
      if(true) //should check here if valid json object.
             {
             //read all full messages
             
             console.log("and so...")
             //o = eval("("+r+")");//creates object from json
             o = JSON.parse(r);// little bit safer [will fail if server.php returns php error or something besides plain json]
             
             console.log(o);
             
             //to inbox all messages (even if only one message it will be index 0 of arrray)
             for(i in o)
               {
               srv_name = o[i][0];
               msg = o[i][1];
               
               console.log(o[i]);
               
               
              if( (srv_name == 'comAgent') &&
                  (msg['set-agent-id'])
                )
                      {
                      this.agentID = msg['set-agent-id'];
                      console.log("New agent ID: "+this.agentID);
                      }//if
                    else
                      {//normal message
                      
                      if(comAgentServiceList[srv_name])
                        {
                         console.log('found service for '+srv_name+'!')
                         console.log(comAgentServiceList[srv_name])
                         
                         //add message to that service queue
                         comAgentServiceList[srv_name].inbox.push(msg);
                         new_message_service_list[srv_name] = true;//remember that this service has a new message, later we'll let it know.
                        }//if
                      else
                        {
                        //this.inbox.push(msg);//we could keep the message in our own lost and found queue
                        }//else
                        
                      }//else               

                      //this.inbox.push(o[i]);//push all messages
               }//for
          
             
             //notify of new messages in inbox (for each service that has new messages)
             
             for(i in new_message_service_list)
               {
               console.log('alerting service of new data..')
               console.log(i)
               comAgentServiceList[i].youveGotNewMessages();
               }
               
//             if(this.notify) 
//               {
//               this.notify(this.inboxLen());
//               }//if
               
             }//else
       
      //ready for the next transfer
      //this.readyXHR(); 2008.05.08 - we're create a new on before each call
      this.transaction = false;//2008.05.08 note that we're not transacting anymore
      
      if(this.processAgain)
       {
       console.log('autoprocessing !!')
       this.processAgain = false;
       this.processMessages();
       }      
      
        // HERE LIKELY WE'LL WANT TO SEE IF WE SHOULD SEND RIGHT AWAY.. (like the send again variable)
        //if(this.outbox.length > 0)
        //  setTimeout("comAgentList["+this.index+"].processMessages()",500);//plan to flush outbox
      }//if

  
  }//function
  
// ********************************************************** //
   
//  comAgent.prototype.setAlert = 
//  function (alerter)
//    {//alerter function will be called when a new message or set of messages are ready to be read.
//    console.log("setting alert");
//    console.log(alerter) 
//    this.notify = alerter;
//    }
    
// ********************************************************** //
   
  comAgent.prototype.setMailCall =   
  function (caller)
    {//alerter function will be called when a new message or set of messages are ready to be read.
    console.log("setting mail call");
    console.log(caller) 
    this.mailCall = caller;
    }
    
    

// ********************************************************** //    
    
  
  comAgent.prototype.newXMLHttpReqObj =  
  function ()
    {//geuf: embeded generic util function
    var xhr;
    if(window.ActiveXObject)
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
      else
        xhr = new XMLHttpRequest();
        
    
    return xhr;
    }//func


// ********************************************************** //    

  //process
  comAgent.prototype.tick =
  function ()
  { // let's review our situation.. 
  var d = new Date();
  var now = d.getTime();
  var dc = now-this.lastCheck; 
  
  console.log(this.outbox.length);
  
  if( 
     (
      (this.outbox.length > 0) && //messages waiting to send
      (dc >= this.MAX_SEND_WAIT)
      ) ||
      (dc >= this.MAX_CHECK_WAIT)
     )
     this.processMessages();
  
  setTimeout("comAgentList["+this.index+"].tick()",this.nextReviewSituationDelay);
  }//func
  
  
  
  
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

// service object might be better off hidden.. and referenced thru
// service names function like...
// postMessage("awk",msg);

function comAgentService(service_name)
{
  //please keep service names unique
  comAgentServiceList[service_name] = this;
  this.serviceName = service_name;
}

comAgentService.prototype.serviceName = false;
comAgentService.prototype.comAgent = false;
comAgentService.prototype.inbox = [];
comAgentService.prototype.messageSendingEventFunc = false;
comAgentService.prototype.messageReadyEventFunc = false;

comAgentService.prototype.messagesReady = 
  function ()
  {
  return this.inbox.length;
  }//func
  
comAgentService.prototype.getMessage = 
  function ()
  {
  return this.inbox.shift();
  }//func
  
comAgentService.prototype.postMessage = 
  function (msg)
  {
  console.log('cas.postingMessage');
  console.log(msg);
  console.log(this.comAgent)
  return this.comAgent.send(this.serviceName,msg);
  }//func
  
comAgentService.prototype.processMessages = 
  function ()
  {//call this to ask for immedate message sending. (but what if it's in the middle of that.)
  //this.comAgent.processMessages();
  return false;
  }//func
  
comAgentService.prototype.messageReadyCall = 
  function (call)
  {
  this.messageReadyEventFunc = call;
  }//func
  
comAgentService.prototype.messageSendingCall = 
  function (call)
  {//last chance to send a message
  this.messageSendingEventFunc = call;
  }//func
  
comAgentService.prototype.youveGotNewMessages =
  function ()
  {
  console.log("you've got new messages!");
  console.log(this)
  if(this.messageReadyEventFunc)
    this.messageReadyEventFunc();
  }
  
////////////////
  var comAgentDefaultAgent = new comAgent(); //-- defer to onload (IE Abort)?
 

