
//AJAX Interface to (port 80 mode) DTS RT System 
//Effectively does what the ActiveX Web Ctrl / Java RT client does.
//Uses XmlHttpRequest object to asynchronously fire off HTTP calls.


Test = 
{
  m_testvar: 0,

  test: function()
  {
    alert("test");
  },

  set: function(val)
  {
    m_testvar = val;
  },

  get: function()
  {
    return m_testvar;
  }
}


//IframeTransportIE is a literal variable, as this is the only way 
//I could stop the IE garbage collector from freeing the htmlfile object.
//Enclosing the iframe transport in a htmlfile object prevents 
//UI from showing loading activity (throbber, cursor, status bar)
//
IfrTrans = 
{
  m_htmlfile: null,

  connect_htmlfile: function(url)
  {
    var htmlfile = new ActiveXObject('htmlfile'); 
    htmlfile.open();
    htmlfile.write('<html><script>' +
                   'document.domain="' + document.domain + '";' +
                   '</'+'script></html>');
    //htmlfile.parentWindow.Orbited = this;
    htmlfile.close();
    var iframe_div = htmlfile.createElement('div');
    htmlfile.body.appendChild(iframe_div);
    iframe_div.innerHTML = '<iframe src="' + url + '"></iframe>';
    this.m_htmlfile = htmlfile;
    var self = this;
	//this.m_htmlfile.parentWindow.udisp = udisp;
	this.m_htmlfile.parentWindow.IfrTrans = IfrTrans;
    function close_htmlfile () {
      htmlfile = null;
      self.m_htmlfile = null;
      CollectGarbage();
    }
    document.attachEvent('on'+'unload', close_htmlfile)
  },

  ifrDisp: function(strSession, strUpdates)
  {
	udisp(strSession, strUpdates);
  }

}


function RtWebClientAjax(objName, bStreaming)
{
//make public methods accessible
  this.AddRequest = AddRequest;
  this.Connect = Connect;
  this.Disconnect = Disconnect;
  this.onTimer = onTimer;
  this.IsStreaming = IsStreaming;
  this.onIframeUpdate = onIframeUpdate;

//defines
  var HTTP_SCRIPT_OBJ = "/rtfcgi-bin/RtHttpFcgi.exe?PostRawCommands";
  var HTTPGET_SCRIPT_OBJ = "/rtfcgi-bin/RtHttpFcgi.exe?RawCommand&";

  var RAWCMDS_FIRSTLINE = "RawCommands:\n";

  var IFRAME_MEM_LIMIT = 100000; //10000; //1000000; //1MB. Maybe consider increasing this to 10MB

  var METHOD_IFRAME = "iframe";
  var METHOD_HTMLFILE = "htmlfile";
  var METHOD_XHR = "xhr";


//public methods
  function AddRequest(strLocation, strRecord, strField, strService)
  {
    //if (!m_bConnected)
    //  return false;

    var strCommand = protocolRequestField(strService, strRecord, strField, strLocation, m_strSession);
    m_strCommands += strCommand;

    return true;
  }

  function Connect()
  { 
    if (m_bStreaming)
	{
	  return ConnectStreaming();
	}

    var strCommand = protocolStartSession("adam","password");
    SendGetCommand(strCommand);

    //startTimer();

    return true;
  }

  function Disconnect()
  {
    //no destructors in JavaScript, so this needs to be called (usually when the page in unloaded)

    if (m_bStreaming)
	  removeIframe();

    if (!m_bStreaming)
      stopTimer();

    var strCommand = protocolEndSession(m_strSession);
    SendCommands(strCommand);
    return true;
  }

  function IsStreaming()
  {
    return m_bStreaming;
  }

  function onIframeUpdate(strContent)
  {
    processUpdates(strContent);

    //TEMP Debug:
//    setDebugMsg(m_iframeMem);
//	document.getElementById("testarea").innerHTML += " " + strContent;

    //Streaming size limit. 
    //Count the characters received. We need to reload the page at the preset limit
    m_iframeMem = m_iframeMem + strContent.length;    
    if (m_iframeMem > IFRAME_MEM_LIMIT)
    {
      scheduleReloadIframe();
      m_iframeMem = 0;
    }

    m_bStreamCapable = true;

    m_timeLastIframeUpdate = new Date();

	scheduleCheckIframe();  //regularly check that the iframe is still responding 
  }


//private methods

  function ConnectStreaming()
  {
    m_strStreamMethod = DetectStreamingMethod();

    var strStartCommand = protocolStartStreamingSession("web","password");

    SendCommandAndQueued(strStartCommand);
  }

  function DetectStreamingMethod()
  {
    // If we're on IE, we want to use an iframe wrapped in a htmlfile
    if(isIE())
      return METHOD_HTMLFILE;

	//If FF, XHR is best
	if (isMozilla())
	  return METHOD_XHR;

    //otherwise use a plain iframe
    return METHOD_IFRAME; 
  }

  function OnHttpResponse()  //XmlHttpRequest callback
  {
    //TODO: parse output html for updates
    //
    if ((m_httpRequest.readyState != 4) || (m_httpRequest.status != 200))
    {
//      alert("HTTP error while posting info:\n" + m_httpRequest.statusText);
      return;
    }

    //get command response
    var sout = m_httpRequest.responseText;
    sout = sout.replace(/<html>[\r\n ]*/i, "");  //remove html header
    var strCmd = sout.substring(0,sout.indexOf(":"));
    if (strCmd == "HSS")   //connected
    {
      m_strSession = sout.substring(4,sout.indexOf("\n"));
      m_bConnected = true;

      onConnected();  //rtScripting hook

      startTimer();

      return;
    }

    //streaming init response.
	if (strCmd == "HST")
	{
      m_strSession = sout.substring(4,sout.indexOf("\n"));
      m_bConnected = true;
	  //g_reqArray[m_strSession] = this;
	  g_reqArray[m_strSession] = g_ajaxClient;
	
      onConnected();  //rtScripting hook

      //start streaming
//	  var strUrl = makeGetStreamingUpdatesUrl(m_strSession);
//    makeAsyncHttpRequest(strUrl, "GET", null);
      initiateStreaming();

      //check to see if streaming is working in 5seconds.
	  setTimeout(checkStreaming, STREAM_INIT_TIMEOUT); //5000);

	  return;
	}

    //if GETUPDATES response
//    document.getElementById("testarea").innerHTML = strCmd;

    if (strCmd == "FU")  
    {
	  processUpdates(m_httpRequest.responseText);
    }

  }

  function processUpdates(strContent)
  {
    //get command response
    var sout = strContent;
    sout = sout.replace(/<html>[\r\n ]*/i, "");  //remove html header
    var strCmd = sout.substring(0,sout.indexOf(":"));

    if (strCmd == "FU")  
    {
      var arrUpdates = sout.split(";");
      while (arrUpdates.length > 0)
      {
        strPair = arrUpdates.pop();
        var nColon = strPair.indexOf(":");
        if (nColon == -1)
          continue;
        var strUpdate = strPair.substring(nColon+1); //discard "FU:" part at the beginning
        arrPair = strUpdate.split("=");  //split into requestId and value parts
        if (arrPair.length != 2)
          continue;
        updateReceived(arrPair[0], arrPair[1]);  //call rtScripting callback.
      }
    }
  }

  function SendGetCommand(strCommand)
  {
    var strUrl = getGetUrl();
	strUrl += strCommand;

    makeHttpRequest(strUrl, "GET", null);
  }

  function SendAsyncGetCommand(strCommand)
  {
    var strUrl = getGetUrl();
	strUrl += strCommand;

    makeAsyncHttpRequest(strUrl, "GET", null);
  }

  function getPostUrl()
  {
    var sc = window.location.href;
    var strRoot = sc.substring(0, sc.indexOf("/", sc.indexOf("//")+2));

    var strUrl = strRoot + HTTP_SCRIPT_OBJ;

	return strUrl;
  }

  function getGetUrl()
  {
    var sc = window.location.href;
    var strRoot = sc.substring(0, sc.indexOf("/", sc.indexOf("//")+2));

    var strUrl = strRoot + HTTPGET_SCRIPT_OBJ;

	return strUrl;
  }

  function makeGetStreamingUpdatesUrl(strSession)
  {
    var strUrl = getGetUrl();
	strUrl += protocolGetStreamingUpdates(m_strSession, IFRAME_MEM_LIMIT);
	
	//remove last character, which is a new line
	strUrl.substring(0, strUrl.length - 1);

	//Adding the date onto the request forces the browser to not use a cached copy.
	//It may also be useful for timing/performance functionality in the future.
	var dt = new Date();
	strUrl += "&t=" + dt.getTime();

	return strUrl;
  }

  function SendCommands(strCommands)
  {
    //fire off XmlHttpRequest

    var strUrl = getPostUrl();

    var strCommandsProto = RAWCMDS_FIRSTLINE + strCommands;

    makeHttpRequest(strUrl, "POST", strCommandsProto);
  }

  function SendQueuedCmds()
  {
//    alert("sendingQueuedCmds: " + m_strCommands);

    var strCommands = m_strCommands;
    m_strCommands = "";
    SendCommands(strCommands);
  }

  //sends command in parameter (Start or GetUpdates command) and also sends queued commands.
  function SendCommandAndQueued(strFirstCommand)
  {
    var strUrl = getPostUrl();

    var strCommandsProto = RAWCMDS_FIRSTLINE;
	strCommandsProto += strFirstCommand;
	strCommandsProto += m_strCommands;

	m_strCommands = "";  //reset outstanding commands

    makeHttpRequest(strUrl, "POST", strCommandsProto);
  }

  function onTimer()
  {
    m_ttGetUpdates -= SLEEP_PERIOD;
    if (m_ttGetUpdates <= 0)
    {
       var strCommand = protocolGetUpdates(m_strSession);
       m_ttGetUpdates = INTERVAL_GETUPDATES;
       //use HTTP GET
       SendGetCommand(strCommand);
       return;
    }

    if (m_strCommands != "") 
      SendQueuedCmds();

  }

  function startTimer()
  {
    var nSleepPeriod = 100;

//    alert(m_objName);
    m_timerId = window.setInterval(m_objName + ".onTimer()", nSleepPeriod);
  }

  function stopTimer()
  {
//    alert("stopTimer");
    if (m_bConnected)
      window.clearInterval(m_timerId);
  }

  function makeHttpRequest(url, type, strContents) 
  {

    m_httpRequest = false;

    if (window.XMLHttpRequest)  // Mozilla, Safari,...
    {
      m_httpRequest = new XMLHttpRequest();
//      if (m_http_request.overrideMimeType) 
//      {
//        m_httpRequest.overrideMimeType('text/xml');
//      }
    } 
    else if (window.ActiveXObject)  // IE
    {
      try 
      {
        m_httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
      } 
      catch (e) 
      {
        try 
        {
          m_httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        } 
        catch (e) {}
      }
    }

    if (!m_httpRequest) 
    {
      alert('Giving up :( Cannot create an XMLHTTP instance');
      return false;
    }

    m_httpRequest.onreadystatechange = OnHttpResponse;
    m_httpRequest.open('POST', url, true);
    m_httpRequest.send(strContents);

  }

  function makeAsyncHttpRequest(url, type, strContents)
  {
    if (m_strStreamMethod == METHOD_XHR)
	  initStreamXhr(url);
	else
	  initStreamReqIframe(url);

  }

  function initiateStreaming()
  {
	var strUrl = makeGetStreamingUpdatesUrl(m_strSession);
	makeAsyncHttpRequest(strUrl, 'GET', null);
	//initStreamReqIframe(strUrl);
  }

  function initStreamXhr(url)
  {
    if (m_xhrStreamer == null)
	  m_xhrStreamer = new XhrStreamer();

	m_xhrStreamer.connect(url);
  }

  //<!--
  function initStreamReqIframe(strUrl)
  {
    //I've had problem with this throbberless IE solution and am disbling it for now.
    //TODO: Look into this and fix it.
    if (isIE()) 
    //if (0) 
    {
      // For IE browsers - embed iframe in a htmlfile object to solve throbber problem
      IfrTrans.connect_htmlfile(strUrl);
/*
      var m_iframeT = new ActiveXObject("htmlfile");
      m_iframeT.open();
      m_iframeT.write("<html>");
//      m_iframe.write("<script>document.domain = '"+document.domain+"'</script>");
      m_iframeT.write("<script>document.domain = '"+document.domain+"'</"+"script>");
      m_iframeT.write("</html>");
      m_iframeT.close();
      var iframediv = m_iframeT.createElement("div");
      m_iframeT.appendChild(iframediv);
      //m_iframe.parentWindow.RtWebClientAjax = this;
	  m_iframeT.parentWindow.udisp = udisp;
      iframediv.innerHTML = "<iframe id='comet_iframe' src='"+strUrl+"' name='comet_iframe'></iframe>";
	  m_iframe = m_iframeT;
	  //this.m_iframe = m_iframeT;
	  //setInterval( function () {}, 1000);
*/
    } 
    else if (navigator.appVersion.indexOf("KHTML") != -1) 
    //if (isIE() || (navigator.appVersion.indexOf("KHTML") != -1))
    {
      // for KHTML browsers
      m_iframe = document.createElement('iframe');
      m_iframe.setAttribute('id', 'comet_iframe');
      m_iframe.setAttribute('src', strUrl);
      m_iframe.setAttribute('name', 'comet_iframe');
      with (m_iframe.style) 
      {
        position   = "absolute";
        left       = top   = "-100px";
        height     = width = "1px";
        visibility = "hidden";
      }
      document.body.appendChild(m_iframe);
    } 
    else 
    {
      // For other browsers, including Mozilla based browsers
      m_iframe = document.createElement('iframe');
      m_iframe.setAttribute('id', 'comet_iframe');
      m_iframe.setAttribute('name', 'comet_iframe');
	  m_iframe.onload = onLoadIframe;
      with (m_iframe.style) 
      {
        left       = top   = "-100px";
        height     = width = "1px";
        visibility = "hidden";
        display    = 'none';
      }
      var iframediv = document.createElement('iframe');
      iframediv.setAttribute('src', strUrl);
      m_iframe.appendChild(iframediv);
      document.body.appendChild(m_iframe);
//	  killLoadBar();
   }
   return true;
  }
  //-->

  function removeIframe()
  {
    var elemIframe = document.getElementById(IFRAME_NAME);
	if (elemIframe != null) 
      elemIframe.parentNode.removeChild(elemIframe);    
  }
  
  function scheduleReloadIframe()
  {
	m_timerIdIframe = setTimeout(reloadIframe, 500);
  }
  
  function reloadIframe()
  {
	clearTimeout(m_timerIdIframe);

    //destroy Iframe    
	removeIframe();

    initiateStreaming();

    //re-create the iframe to reload (just setting the href does not work - see below).
//	var strUrl = makeGetStreamingUpdatesUrl(m_strSession);
//	initStreamReqIframe(strUrl);

    //make the iframe open a new page:
//    window.frames[IFRAME_NAME].location.href = strUrl;
//    window.frames[IFRAME_NAME].location.reload(true);

//    setTimeout(hideIframeLoadCursor, 500);
  }

  function hideIframeLoadCursor()
  {
    window.frames[IFRAME_NAME].location.href = strUrl;
    window.frames[IFRAME_NAME].location.reload(true);
  }

  function checkStreaming()
  {
    var strMsg = m_bStreamCapable ? "Streaming enabled" : "Polling mode";
    setStatusMsg(strMsg);

//	m_bStreamCapable = false; //TEMP: forcing to switch to poll

    if (!m_bStreamCapable)
	{
	  //cancel streaming and do polling instead
	  removeIframe();
	  startTimer(); //polling timer
	}
  }

  //CheckIframe timer functions: checks readyState of iframe to make sure the iframe is still responding

  function scheduleCheckIframe()
  {
    if (m_timerIdCheckIframe != 0)
	  clearTimeout(m_timerIdCheckIframe);

	m_timerIdCheckIframe = setTimeout(checkIframe, IFRAME_TIMEOUT); //check in 1s.
  }

  function checkIframe()
  {
//    setDebugMsg("iframe ready state = " + window.frames[IFRAME_NAME].document.readyState);

//	if (window.frames[IFRAME_NAME].document.readyState != "unknown")  //loading
//	{
//	   //setStatusMsg("IFrame no longer loading, so we should do a reload here!");
//	}

    //we obviously haven't had an update since for as long as the timeout, otherwise this function wouldn't have been called.
	//so, let's reload the iframe. 
	reloadIframe();
	setDebugMsg("reloading iframe after the iframe_timeout was reached");

	scheduleCheckIframe();
  }

  function onLoadIframe()
  {
//    setStatusMsg("onLoadIframe() called.");
  }

  function setDebugMsg(strMsg)
  {
    var elemDebug = document.getElementById("testarea");
	if (elemDebug != null)
      elemDebug.innerHTML = strMsg;
  }
  
  function setStatusMsg(strMsg)
  {
    var elemStatus = document.getElementById(ID_STATUS_AREA);
	if (elemStatus != null)
      elemStatus.innerHTML = strMsg;
  }

  function hideIframe(ifr)
  {
    ifr.style.display = 'block';
    ifr.style.width = '0';
    ifr.style.height = '0';
    ifr.style.border = '0';
    ifr.style.margin = '0';
    ifr.style.padding = '0';
    ifr.style.overflow = 'hidden';
    ifr.style.visibility = 'hidden';
  }

  function killLoadBar()
  {
//    if (typeof m_loadKillIfr === 'undefined') 
//	{
      m_loadKillIfr = document.createElement('iframe');
      hideIframe(m_loadKillIfr);
//    }
    document.body.appendChild(m_loadKillIfr);
    document.body.removeChild(m_loadKillIfr);
  }

//private members
  var m_strCommands = "";  
  var m_bConnected = false;
  var m_strSession = "";
  var m_timerId = 0;
  var SLEEP_PERIOD = 100;  //milliseconds
  var INTERVAL_GETUPDATES = 1000; //milliseconds
  var STREAM_INIT_TIMEOUT = 2000;
  var m_httpRequest = false;
  var m_ttGetUpdates = INTERVAL_GETUPDATES;
  var m_objName = objName;
  var m_bStreaming = bStreaming;
  var m_iframe = null;
  //this.m_iframe = null;
  var IFRAME_NAME = "comet_iframe";
  var m_nDispId = 0;
  var m_iframeMem = 0;
  var m_timerIdIframe = 0;
  var m_timerIdCheckIframe = 0;
  var m_bStreamCapable = false;
  var m_timeLastIframeUpdate; 
  var IFRAME_TIMEOUT = 10000; //10seconds
  var m_loadKillIfr = null;
  var m_strStreamMethod = "";
  var m_xhrStreamer = null;
}


function XhrStreamer()
{
  //public methods
  this.connect = connect;

  function connect(url)
  {
    if (m_xhr != null)
	{
	  m_xhr.abort();
	  m_xhr = null;
	}
    
	m_xhr = create_xhr();

    m_nLengthSeen = 0;
    m_nLengthParsed = 0;

    m_xhr.onreadystatechange = function () 
	{
      try {
        if (m_xhr.status != 200) {
          //log('xhr failed (status not 200)');
          return false;
        }
      }
      catch(e) {
        return false;
      }
      // We have some new data
      if (m_xhr.readyState == 3) {
        handle_data();
      }
      // Connection is finished.
      if (m_xhr.readyState == 4) {
        handle_data();
      }
    };
    m_xhr.open('GET', url, true);
    m_xhr.send(null);
  }

  function handle_data()
  {
    var response_stream = m_xhr.responseText;

    // If there's no new text, bail out.
    if (response_stream.length === m_nLengthSeen) 
      return;

    var nStart = response_stream.indexOf("<script>", m_nLengthParsed);
    var nEnd = response_stream.lastIndexOf("</script>");
	if ((nStart > -1) && (nEnd > m_nLengthSeen))
	{
	  var strSegment = response_stream.substring(nStart, nEnd);
	  strSegment = strSegment.replace(/<script>/g," ");
	  strSegment = strSegment.replace(/<\/script>/g," ");
	  eval(strSegment);  //TODO: possibly parse each update individually.
	  m_nLengthParsed = nEnd + 9;
	}

    m_bStreamCapable = true;

    m_nLengthSeen = response_stream.length;

  }

  //private methods:
  function create_xhr() 
  {
    try { return new ActiveXObject('MSXML3.XMLHTTP'); } catch(e) {}
    try { return new ActiveXObject('MSXML2.XMLHTTP.3.0'); } catch(e) {}
    try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
    try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
    try { return new XMLHttpRequest(); } catch(e) {}
    throw new Error('Could not find XMLHttpRequest or an alternative.');
  }

  //private members:
  var m_xhr = null;
  var m_nLengthSeen = 0;
  var m_nLengthParsed = 0;
}


//dispatching iframe updates to appropriate requester objects.

var g_reqArray = new Array();
var g_nLastDispId = 0;
function udisp(strSessionId, strUpdate)
{
//  gsetDebugMsg("udisp called with: " + strUpdate);
  g_reqArray[strSessionId].onIframeUpdate(strUpdate);
}


//  function gsetDebugMsg(strMsg)
//  {
//    var elemDebug = document.getElementById("testarea");
//	if (elemDebug != null)
//      elemDebug.innerHTML = strMsg;
//  }
  



//protocol functions

function protocolStartSession(strUsername, strPassword)
{
  var strVersion = "1";
  var strAppName = "WebClientAjax";
  var strProto = "HSS:" + strVersion + ";" + strAppName + ";" + strUsername + ";" + strPassword + "\n";
  return strProto;
}

function protocolEndSession(strSession)
{
  var strProto = "HES:" + strSession + "\n";
  return strProto;
}

function protocolRequestField(strService, strRecord, strField, strLocation, strSession)
{
  var strProto = "RQF:" + strService + ";" + strRecord + ";" + strField + ";" + strLocation + ";" + strSession + "\n";
  return strProto;
}

function protocolReleaseField(strLocation, strSession)
{
  var strProto = "RLF:" + strLocation + ";" + strSession + "\n";
  return strProto;
}

function protocolGetUpdates(strSession)
{
  var strProto = "HGU:" + strSession + "\n";
  return strProto;
}

function protocolStartStreamingSession(strUsername, strPassword)
{
  var strVersion = "1";
  var strAppName = "WebClientAjax";
  var strProto = "HST:" + strVersion + ";" + strAppName + ";" + strUsername + ";" + strPassword + "\n";
  return strProto;
}

function protocolGetStreamingUpdates(strSession, strLimit)
{
  var strProto = "HGT:" + strSession + ";" + strLimit + "\n";
  return strProto;
}


////////////// General functions ///////////////////////////

function isIE()
{
  return (typeof window.ActiveXObject != 'undefined');
}  
  
function isMozilla()
{
  return  (typeof document.implementation != 'undefined') &&
          (typeof document.implementation.createDocument != 'undefined');
}
  
