//******************************** CGI NovaCmd Info: ********************************//
//Commands Info:    SendNovaCmd, ScheduleCmds
//  SendNovaCmd does not garuantee that the command will be sent and may return false 
//    if sending is busy, use this if you do not care if the data makes it through.
//    Hint: This is good for regularly scheduled cmds
//  ScheduleCmds will ensure that the command gets sent to the unit and will continue 
//    to try to send it up failure, however calling this too many times too quickly 
//    can cause a queueing effect where the commands do not get sent as quickly as
//    they are scheduled, which causes problems.
//    Hint: This is good for event driven cmds
//
//Args Info:        cmd, timeout, blocking
//  cmd: this could be a single string or an array of strings (10 max)
//    if a single string is specified, then only one command will be sent
//    if a list is specified, then all the messages in the list will be sent with
//    the same request. If more than 10 are in the list, then SendNovaCmd will 
//    only send the first 10. ScheduleCmds will schedule the messages 10 at a time.
//  timeout: specifies how long the receiver should wait for the response to come
//    if not specified, the receiver will use its default, current set to 1.2 seconds
//  blocking: if false, then the receiver will not wait the entire timeout period
//    but will return the first response it receives.
//    If true, then the receiver will wait the entire timeout period regardless of
//    how many messages it receives.
//    Hint: use false with a small timeout for commands with ignored responses, or
//      with no responses, or with quick responses. Use false with a long timeout if
//      the response of the command takes a while to return.
//    Hint: use true with commands that will return large data with a pause inbetween
//      the data transmission, or when sending multiple commands that will have their
//      own response.
//    Hint: Try to avoid using large timeout with blocking option as much as possible
//      because such combination will hold up the queue on the receiver end
//**********************************************************************************//

//Globals
var xmlDoc;
var page;
var msgs = new Array();
var gotResponse = true;
var lastSentRequest;
var waitingTime = 2000;
var maxCmds = 10;

function initXMLDoc(pageIn, msgIn)
{
   xmlDoc = createXMLHttp();
   page = pageIn;
   if(msgIn)
      msgs.push(msgIn);
  
   xmlDoc.onreadystatechange = updateForm;
}

function addListenerObj(msgIn)
{
   msgs.push(msgIn);
}

function updateForm()
{
   if (xmlDoc.readyState==4 && xmlDoc.status==200)
   {
      var i;
      for(i = 0; i < msgs.length; i++)
      {
         if( msgs[i].update(xmlDoc.responseText) )
            page.format(msgs[i]);
      }
      gotResponse = true;
   }
}

function createXMLHttp() 
{
   if (typeof XMLHttpRequest != 'undefined')
      return new XMLHttpRequest();
   else if (window.ActiveXObject) {
      var avers = ["Microsoft.XmlHttp", "MSXML2.XmlHttp", "MSXML2.XmlHttp.3.0", "MSXML2.XmlHttp.4.0", "MSXML2.XmlHttp.5.0"];
      for (var i = avers.length - 1; i >= 0; i--) {
         try {
            httpObj = new ActiveXObject(avers[i]);
            return httpObj;
         } catch (e) { }
      }
   }
   throw new Error('XMLHttp (AJAX) not supported');
}

function GetCmdStr(cmd)
{
   //change to ascii hex representation
   cmd = cmd.replace(/\s/g, "%20");
   cmd = cmd.replace(/\?/g,  "%3F");
   return "?novacmdname=" + cmd;
}

function SendNovaCmd(cmd, timeOut, blocking)
{
   var timeOutStr = "";
   var blockingStr = "";
   var cmdStr = "";
   if(timeOut)
      timeOutStr = "&timeout=" + timeOut;
   if(blocking)
      blockingStr = "&blocking=" + ((blocking) ? '1' : '0');
   if(typeof cmd == 'string')
   {
      cmdStr += GetCmdStr(cmd);
   }
   else
   {
      for(cmdi=0; cmdi<cmd.length && cmdi<maxCmds; cmdi++)
      {
         cmdStr += GetCmdStr(cmd[cmdi]);
      }
   }
   return SendCgiRequeset("/novacmd.cgi" + cmdStr + timeOutStr + blockingStr);
}
function SendBinaryCmd(url, cmdArray, cmdLen, holdForResp) {
    var ajaxSend = (holdForResp) ? false : true;
    xmlDoc.open("POST", url, ajaxSend);
    xmlDoc.setRequestHeader("Content-Length", cmdLen);
    xmlDoc.onreadystatechange = updateForm;
    // cmdArray is a Uint8Array typed array but its length is
    // fixed to the value used in the constructor.  Even though 
    // Content-Length is set to the value of cmdLen the send method
    // still sends the full size of the cmdArray buffer and sends that
    // same value in Content-Length.  As a workaround if cmdLen does
    // not equal cmdArray.length create a new Uint8Array of the correct
    // size and copy the data to it.
    if (cmdLen != cmdArray.length) {
        var newArray = new Uint8Array(cmdLen);
        for (var i = 0; i < cmdLen; i++) {
            newArray[i] = cmdArray[i];
        }
        xmlDoc.send(newArray.buffer);
    } else {
        xmlDoc.send(cmdArray.buffer);
    }
}
function SendCgiRequeset(xml_file) 
{
   //if we already got a response OR
   //if we we have already timed out and gone over the waiting limit
   // -> then we are able to send
   if( gotResponse || ((new Date()).getTime() - lastSentRequest) > waitingTime )
   {
      // true is asynchronous connection
      xmlDoc.open("GET", xml_file, true);
      xmlDoc.onreadystatechange = updateForm;
      xmlDoc.send();
      
      lastSentRequest = (new Date()).getTime()/1;
      gotResponse = false;
      
      return true;
   }
   else
   {
      return false;
   }
}
//could schedule multiple commands, guaranteed to be sent
function ScheduleCmds(cmd, timeOut, blocking)
{
   var count = 0;
   var cmdList = (typeof cmd == 'string') ? [cmd] : cmd;
   var intID = setInterval(
      function () {
         if(count < cmdList.length)
         {
            if( SendNovaCmd(cmdList.slice(count, count+maxCmds), timeOut, blocking) )
            {
               count+=maxCmds;
            }
         }
         else
         {
            clearInterval(intID);
         }
      }, 
      100
   );
}
//function to send false information to logout the current user
function logout()
{
   // true is asynchronous connection
   xmlDoc.open("GET", "/", true, "user", 'whatyoucallabadpassword');
   xmlDoc.onreadystatechange = updateForm;
   xmlDoc.send();
}

//a short function to call document.getElementById()
function getById(str)
{
   return document.getElementById(str);
}

//firsts trims the leading/trailing spaces, and then gets rid of any quotes
function cleanUpArgList(args)
{
   for(argi=0; argi<args.length; argi++)
      args[argi] = args[argi].replace(/^\s+|\s+$/g,'').replace(/"/g,'');
   return args;
}

//put the standard ascii parser with xmlHandler since every page could potentially use it
// this.input   = the entire message receieved
// this.name    = the name of the command, ie. [OUTPUT]
// this.msg     = the (first) message following the command name until \r\n, ie. PVT1B,ONCHANGE
// this.arg     = an array of the command args, ie. [PVT1B, ONCHANGE]
// this.msgList = an array of all the messages, incase there are more than one msg returned
// this.argList = an 2D array of args in each of the returned commands, ie. [[PVT1B, ONCHANGE],[MEAS1B, ONCHANGE]]
function standardMsg_obj(commandName)
{
   var MsgName = commandName;
   this.msg = "";
   
   this.update = function(input)
   {      
      var start = input.indexOf(MsgName);

      //don't start parsing if this is not the right message
      if(start < 0)
      {
         return false;
      }
      this.name = MsgName;
      this.input = input.substring(start);
      start += MsgName.length;
      
      //whatever you get, spit it back
      
      msgLine = input.substring(start).split("\r\n");
      this.msg = msgLine[0]; //set the message up to the crlf
      this.arg = cleanUpArgList(this.msg.split(','));

      this.msgList = [];
      this.argList = [];
      for(i=0; i<msgLine.length; i++)
      {
         msgLine[i] = msgLine[i].replace(MsgName, "");
         this.msgList.push(msgLine[i]);
         this.argList.push(cleanUpArgList(msgLine[i].split(',')));
      }
      return true;
   }
}
