//
//    From the body "onload", it should call "initialize()",
//    which is the first function in this script.
// 
// Author: Mike Bergsma
//
// Modifications:
//
//   $Log: DASHapi.js,v $
//   Revision 1.44  2009-04-20 22:08:09  bergsma
//   no message
//
//   Revision 1.43  2009-04-15 14:58:01  bergsma
//   no message
//
//   Revision 1.42  2009-04-10 05:23:01  bergsma
//   Just keeping things cvs'd
//
//   Revision 1.41  2009-04-04 18:07:32  bergsma
//   no message
//
//   Revision 1.40  2009-03-24 09:33:46  bergsma
//   no message
//
//   Revision 1.39  2009-01-23 14:24:43  bergsma
//   Change polling timeout restart from 6 to 9 seconds
//
//   Revision 1.38  2008-12-28 00:23:39  bergsma
//   *** empty log message ***
//
//   Revision 1.37  2008-12-18 08:36:44  bergsma
//   no message
//
//   Revision 1.35  2008-11-06 15:16:50  bergsma
//   Cleanup "gen" controls tables
//
//   Revision 1.34  2008-08-24 18:05:39  bergsma
//   no message
//
//   Revision 1.33  2008-06-30 05:19:05  bergsma
//   no message
//
//   Revision 1.32  2008-06-29 18:29:11  bergsma
//   *** empty log message ***
//
//   Revision 1.31  2008-06-27 04:09:18  bergsma
//   no message
//
//   Revision 1.30  2008-06-22 18:31:13  bergsma
//   no message
//
//   Revision 1.29  2008-05-16 20:30:49  bergsma
//   *** empty log message ***
//
//   Revision 1.28  2008-05-15 18:15:42  bergsma
//   *** empty log message ***
//
//   Revision 1.27  2008-05-15 18:04:49  bergsma
//   no message
//
//   Revision 1.19  2008-01-22 05:19:28  bergsma
//   no message
//
//

// If the onload attribute exists in the HTML document on
// the BODY tag, then the following statement is overridden
// by that. 
window.onload = initialize;

// Global Variables
var isDOM_HS = 0 ;	// If HyperScript runs 
var sb_sessionid ;	// Secret session id
var sb_username ;	// The username
var protocol = "https"  // We are doing http over SSL
var dashObject = new Array() ;
var panelArray = new Array() ;
var keyOBJ = null ;
var focusOBJ = null ;

var checkupInterval = 5000 ; // Every 5 seconds, check for pending output
var pollingInterval = 7000 ; // Every 7 seconds, issue another GET
var delayInterval   = 3000 ; // Wait 3 seconds after last PUT before polling
var pollingTimeout  = 8000 ; // This is 3 seconds past the server setting (5) 
var commandTimeout  = 5000 ; // Allow 5 seconds for result of cmd to return.
var connectTimeout  = 10000 ; // Allow 10 seconds to connect

var dashId ;

var doPolling = false ;
var doCheckup = false ;

var delayedPut = false ;
var delayBuf = "" ;
var delayFormat = "" ;
var delayName = "" ;

var delayedMP = false ;
var delayMP = "" ;

var ajaxRequest ;
var ajaxRequest1 ;
var ajaxRequest2 ;

function initialize() 
{
  // Called when window is loaded.

  initHandlers() ;

  // Initialize each subsystem

  // See DHTMLapi.js
  initDHTMLapi() ;

  // See DASHap.js
  initDASHapi() ;

  // See XMLapi.js
  initXMLapi() ;

  // See VTapi.js
  initVTapi() ;

  // See DRAGapi.js
  initDRAGapi() ;

  // See HSapi.js
  initHSapi() ;

  return ;
}

function initDASHapi()
{
  ssid = readCookie('SB_SESSIONID') ;
  sb_sessionid = ssid.substring(1,ssid.length-1);

  usid = readCookie('SB_USERNAME') ;
  sb_username = usid.substring(1,usid.length-1);

  var dashboard = getRawObject('dashboard') ;

  ajaxRequest1    = new HttpXMLRequest() ;
  ajaxRequest2    = new HttpXMLRequest() ;
  ajaxRequest = ajaxRequest1 ;

  // Self-check the AJAX polling engine every few seconds
  doCheckup = true ;
  vtIntervalID = window.setInterval(do_checkup,checkupInterval) ;

  // Connect to the securebob location
  connectBob() ;

}

function nextRequest()
{
  if ( ajaxRequest == ajaxRequest1 ) 
    ajaxRequest = ajaxRequest2 ;
  else
    ajaxRequest = ajaxRequest1 ;

  return ajaxRequest ;
}

function initHandlers()
{
  if ( document.layers && document.captureEvents ) {
    document.captureEvents( Event.KEYUP |
                            Event.KEYDOWN |
                            Event.KEYPRESS |
                            Event.MOUSEUP |
                            Event.MOUSEOVER |
                            Event.MOUSEOUT |
                            Event.MOUSEDOWN ) ;
  }

  document.onkeyup     = vt_handler_keyup ;
  document.onkeydown   = vt_handler_keydown ;
  document.onkeypress  = vt_handler_keypress ;
  document.onmousedown = drag_handler_clickIt;
  document.onmousemove = drag_handler_dragIt;
  document.onmouseup   = drag_handler_releaseIt;
  window.onresize      = drag_handler_moveIt ;
}

/////////////////////////////////////////////////////////////
//
// DASHBOARD AJAX Interface
//
//////////////////////////////////////////////////////////////

function  doFlashCell()
{
  if ( focusOBJ && focusOBJ.hasKeys() ) focusOBJ.flashCell() ;
} 

function doFlushKeys()
{
  if ( focusOBJ ) {
    if ( focusOBJ.loadKeys() ) {
      issuePut ( focusOBJ.getName(), focusOBJ.getKeyBuf(), "KEY" ) ;
    }
  }
}

function vtConnect(evt) {

  evt = (evt) ? evt : event;
  var target = (evt.target) ? evt.target : evt.srcElement;
  if ( target ) {

    // Get the object in question.
    focusObject ( target.name ) ;

    nextRequest() ;

    var host = focusOBJ.getHostValue() ;
    var port = focusOBJ.getPortValue() ;

    var xmldata = 
	"<?xml version='1.0' encoding='UTF-8'?>"+
		"<xmldata><host>" +
		host + "</host><port>" +
		port + "</port></xmldata>" ;

    ajaxRequest.setSuccessHandler ( 'conHandler' ) ;
    ajaxRequest.setTimeoutHandler ( 'conTimeout' ) ;
    ajaxRequest.setName ( '$CONNECT' ) ;
    ajaxRequest.loadXMLDocSync( "POST","/CONNECT_VT", xmldata, connectTimeout ) ;
  }

  return ;
}

function disHandler ( req ) 
{
  return ;
}

function disTimeout ( req ) 
{
  return ;
}

function conHandler ( req ) 
{
  var xmldoc = req.responseXML()  ;
  var xmlcmd = getElementNodeNS ( "" , "xmlconnect" , xmldoc, 0 ) ;
  if ( xmlcmd && xmlcmd.length > 0 ) processActions ( xmlcmd ) ;
  return ;
}

function conTimeout(req)
{
 alert ( "Failed to connect" ) ;
}

function disablePollingForPut( name, buf, format )
{
  doPolling = false ;
  delayedPut = false ;

  var getState = ajaxRequest.getReadyState() ;
  var getName = ajaxRequest.getName() ;
  debug ( 'Current state of '+getName+' is '+getState, 3);

  if ( getState > 0 ) {

    // Current one is busy, let's try the other one
    nextRequest() ;
    getState = ajaxRequest.getReadyState() ;
    getName = ajaxRequest.getName() ;
    debug ( 'Current state of '+getName+' is '+getState, 3);

    if ( getState > 0 ) {
      // Busy as well.
      debug ( 'Delaying put request', 3);
      delayedPut = true ;
      delayName = name ;
      delayBuf = buf ;
      delayFormat = format ;
    }
  }
}

function disablePollingForMP ( fullPanelName )
{
  doPolling = false ;
  //if ( vtIntervalID ) window.clearInterval ( vtIntervalID ) ; 
  //vtIntervalID = null ;
  delayedMP = false ;
  var getState = ajaxRequest.getReadyState() ;
  var getName = ajaxRequest.getName() ;
  debug ( 'Current state of '+getName+' is '+getState, 3);

  if ( getState > 0 ) {

    // That one is busy, try the other one
    nextRequest() ;

    getState = ajaxRequest.getReadyState() ;
    getName = ajaxRequest.getName() ;
    debug ( 'Current state of '+getName+' is '+getState, 3);

    if ( getState > 0 ) {
      debug ( 'Delaying makepanel request', 3);
      delayedMP = true ;
      delayMP = fullPanelName ;
    }
  }
}

function enablePolling()
{
  doPolling = true ;
  if ( !vtIntervalID ) vtIntervalID = window.setInterval(do_checkup,checkupInterval) ;
}

function disablePolling()
{
  doPolling = false ;
  if ( vtIntervalID ) window.clearInterval ( vtIntervalID ) ; 
}

function issueGet()
{
  // This is both the timeout function and the one
  // we launch the alternating get requests.

  if ( !doPolling ) {
    debug('GET requests are disabled',3);
    return ;
  }

  if ( delayedPut ) {
    delayedPut = false ;
    issuePut(delayName,delayBuf,delayFormat) ;
  }
  else if ( delayedMP ) {
    delayedMP = false ;
    makePanel ( delayMP ) ;
  }

  debug('new GET request',3);
  nextRequest() ;

  var xmldata = 
    "<?xml version='1.0' encoding='UTF-8'?>"+
    "<xmldata><cmd>$GET</cmd><format>GET</format><name>$NAME</name></xmldata>" ;

  ajaxRequest.setSuccessHandler ( 'getHandler' ) ;
  ajaxRequest.setTimeoutHandler ( 'getTimeout' ) ;
  ajaxRequest.setName ( '$GET' ) ;

  // The TIMEOUT should be 2 seconds past what the SERVER timeout
  // is for outstanding $GET requests.  In other words, the server
  // will automatically fulfil the reply within 5 seconds of receiving
  // the $GET so that this 7 second timeout should never occur. 
  ajaxRequest.loadXMLDocAsync( "POST","/OUT_BOB", xmldata, pollingTimeout ) ;
}

function putTimeout (req)
{
  var rstate = req.getReadyState() ;
  // focusOBJ has been noticed to be null on an occasion, problably should be tested/fixed
  debug("PUT Timeout!, readystate="+rstate+", KB='"+focusOBJ.getKeyBuf()+"'",2 ) ;
}

function issuePut( name, buf, format ) 
{
  nextRequest() ;

  disablePollingForPut(name,buf,format) ;

  if ( delayedPut ) return ; 

  // Issue new request 
  debug('new PUT request "'+buf+'" for '+name,3);
  var xmldata = 
	"<?xml version='1.0' encoding='UTF-8'?>"+
	"<xmldata><cmd>" +
	buf +
	"</cmd><format>" + 
	format + 
	"</format><name>" + 
	name + "</name></xmldata>" ;

  ajaxRequest.setSuccessHandler ( 'putHandler' ) ;
  ajaxRequest.setTimeoutHandler ( 'putTimeout' ) ;
  ajaxRequest.setName ( name ) ;

  // The TIMEOUT should be just a few seconds because $PUT requests
  // are always fulfilled by the server immediately.
  ajaxRequest.loadXMLDocAsync( "POST","/OUT_BOB", xmldata, commandTimeout ) ;

}

function loadSend(evt)
{
  // Invoked by pressing the [Send] button
  // We have to find out which object that was.
  evt = (evt) ? evt : event;
  var target = (evt.target) ? evt.target : evt.srcElement;
  if ( target ) {

    // Get the object in question.
    focusObject ( target.name ) ;

    // Prepare the send buffer.
    focusOBJ.setLineBuf( focusOBJ.getInputValue() ) ;

    // The original input is cleared.
    focusOBJ.setInputValue("");

    // Now send the data
    issuePut ( target.name, focusOBJ.getLineBuf(), "PUT" ) ;
  }
}


function getHandler ( req ) 
{
  // Asynchronous input
  debug( "getHandler()",3  );
  var xmldoc = req.responseXML()  ;

  var xmlget = getElementNodeNS ( "" , "xmldata" , xmldoc, 0 ) ;

  if ( xmlget && xmlget.length > 0 ) processActions ( xmlget ) ;

  if ( checkBusy(false) ) return ;

  enablePolling() ;
  issueGet() ;

}

function getTimeout (req)
{
  // This is the timeout function and the one
  debug('GET timeout!!!',2);
}

function cmdHandler ( req ) 
{
  // Result from page or scroll operation
  var xmldoc    = req.responseXML()  ;
  var xmlcmd = getElementNodeNS ( "" , "xmlcmd" , xmldoc, 0 ) ;

  if ( xmlcmd && xmlcmd.length > 0 ) {

    processActions ( xmlcmd ) ;

    // Do nothing more.
  }
}

function putHandler ( req ) 
{
  // Result fron key stroke operation
  var xmldoc  = req.responseXML()  ;
  var xmlput = getElementNodeNS ( "" , "xmldata" , xmldoc, 0 ) ;

  if ( !xmlput || xmlput.length == 0 ) return ;

  var name = req.getName() ;
  debug("PUT request for "+name+" returned results",3);
  processActions ( xmlput ) ;
  debug("...done",3);

  var fo = dashObject[name] ;
  if ( fo == null ) return ;

  if ( fo.getLineBuf() != "" )
    // Clear the vt_lineBuf, so more can be sent
    fo.resetLineBuf() ;
  else if ( fo.getKeyBuf() != "" ) 
    // Clear the vt_keyBuf, so more can be sent
    fo.resetKeyBuf() ;

  if ( checkBusy(false) ) {
    debug("Still busy,returning",3);
    return ;
  }

  // Enable polling but don't issue another GET, perhaps
  // the user is still typing and we want to maintain the flow of it.
  enablePolling() ;

  return ;
}

function processActions( xmldata )
{       
  //var output = "Data received:\n" ;
  debug("Processing actions",3);

  doCheckup = false ;

  // We'll restore focusOBJ back when process actions are done!.
  keyOBJ = focusOBJ ;

  // Get array of tags for first (and only) element "xmldata"
  //var pNodes = xmldata[0].childNodes ;
  var pNodes = xmldata ;

  var np, nn, nv ;
  var cp, cpn, cn, cv ;
  var gp, gpn, gn, gv ;

  for ( var i=0; i<pNodes.length; i++ ) {
	  
    np = pNodes[i]
    nn = np.nodeName ;
    debug(nn,3);

    if ( nn == "bytesIn" ) {

//      if ( focusOBJ ) {
//        nv = np.firstChild.nodeValue ;
//        var tn = document.createTextNode ( nv ) ;
//        focusOBJ.setBytesIn ( tn ) ;
//      }
    }
    else if ( nn == "bytesOut" ) {

//      if ( focusOBJ ) {
//        nv = np.firstChild.nodeValue ;
//        var tn = document.createTextNode ( nv ) ;
//        focusOBJ.setBytesOut ( tn ) ;
//      }
    }

    else if ( nn == "status" ) {

 //     if ( focusOBJ ) {
        //nv = np.firstChild.nodeValue ;
        //var tn = document.createTextNode ( nv ) ;
        //var child = focusOBJ.vt_status.firstChild ;
        //if ( child )
        //  focusOBJ.vt_status.replaceChild( tn, child ) ; 
        //else
        //  focusOBJ.vt_status.appendChild( tn ) ;
//      }
    }
    else if ( nn == "pageno" ) {

//      if ( focusOBJ ) {
//        nv = np.firstChild.nodeValue ;
//        var tn = document.createTextNode ( nv ) ;
//        focusOBJ.setPageNo ( tn ) ;
//      }
    }

    else if ( nn == "lineno" ) {

//      if ( focusOBJ ) {
//        nv = np.firstChild.nodeValue ;
//        var tn = document.createTextNode ( nv ) ;
//        focusOBJ.setLineNo ( tn ) ;
//      }
    }

    else if ( nn == "clocktime" ) {

//      if ( focusOBJ ) {
//        nv = np.firstChild.nodeValue ;
//        var tn = document.createTextNode ( nv ) ;
//        var child = focusOBJ.vt_asctime.firstChild ;
//        if ( child )
//          focusOBJ.vt_asctime.replaceChild( tn, child ) ; 
//        else
//          focusOBJ.vt_asctime.appendChild( tn ) ;
//      }
    }

    else if ( nn == "makepanel" ) {

      nv = np.firstChild.nodeName ;

      // Get array of tags for element "makepanel"
      var cNodes = np.childNodes ;

      var m_name = " ";
      var m_type  = " " ;

      for ( var j=0; j<cNodes.length; j++ ) {

  	cp = cNodes[j] ;
        cn = cp.nodeName ;
        cv = cp.childNodes ;

        if ( cv.length > 0 )
          gv = cv[0].nodeValue ;
         else
          gv = "" ;

	if ( cn == "panelName" )
	  m_name = gv ;
	else if ( cn == "panelType" )
	  m_type = gv ;

      }
      makePanel ( m_type + "_" + m_name ) ;

    }

    else if ( nn == "focus" ) {

      nv = np.firstChild.nodeValue  ;

      // See if there is an element by the
      // id of focus.vt_<nv> where nv == chat_x or telnet_x
      focusOBJ = focusObject ( nv ) ;
	
    }

    else if ( nn == "moveto" ) {

      if ( focusOBJ ) {

        nv = np.firstChild.nodeName ;

        // Get array of tags for element "moveto"
        var cNodes = np.childNodes ;
        var x_x = 1 ; 
        var x_y = 1 ;

        for ( var j=0; j<cNodes.length; j++ ) {

          cp = cNodes[j] ;
          cn = cp.nodeName ;
          cv = cp.childNodes ;

          if ( cv.length > 0 )
            gv = cv[0].nodeValue ;
          else
            gv = "" ;

          if ( cn == "x" )
	    x_x = parseInt(gv) ;
	  else if ( cn == "y" )
  	    x_y = parseInt(gv) ;
	

        }
	// Must move the frame of the object.
	shiftTo ( getRawObject( focusOBJ.getFrame() ) , x_x, x_y ) ;
      }
    }
          
    else if ( nn == "cursor" ) {

      if ( focusOBJ && focusOBJ.hasKeys() ) {

        nv = np.firstChild.nodeName ;

        // Get array of tags for element "cursor"
        var cNodes = np.childNodes ;
        var x_row = 1; 
        var x_col = 1 ;
        var x_chr = " ";
        var x_rendition = 0 ;
        var x_flags3 = 0 ;
        var x_graphics = 0 ;

        for ( var j=0; j<cNodes.length; j++ ) {

          cp = cNodes[j] ;
          cn = cp.nodeName ;
          cv = cp.childNodes ;

          if ( cv.length > 0 )
            gv = cv[0].nodeValue ;
          else
            gv = "" ;

          if ( cn == "row" )
	    x_row = parseInt(gv) ;
	  else if ( cn == "col" )
  	    x_col = parseInt(gv) ;
	  else if ( cn == "rendition" )
	    x_rendition = parseInt(gv) 
	  else if ( cn == "graphics" )
	    x_graphics = parseInt(gv) ;
	  else if ( cn == "flags3" )
	    x_flags3 = parseInt(gv);
	  else if ( cn == "chr" )
	    x_chr = gv ;

          //output += cn + "=" + gv + "\n" ;

        }
        if ( focusOBJ.hasKeys() ) 
	  focusOBJ.setFlash( 	x_row, 
				x_col, 
				x_chr, 
				x_rendition, 
				x_graphics, 
				x_flags3, 
				focusOBJ.rv() ) ;
      }
    }
          
    else if ( nn == "actions" && np.firstChild ) {

      if ( focusOBJ ) {

        var x_row = 1; 
        var x_col = 1 ;
        var x_text = " ";
        var x_colspan = 1 ;
        var x_rendition = 0 ;
        var x_flags3 = 0 ;
        var x_graphics = 0 ;	   
        var x_startrow = 1 ;
        var x_endrow = 24 ;

        nv = np.firstChild.nodeName ;

        // Get array of tags for element "actions"

        var cNodes = np.childNodes ;

        for ( var j=0; j<cNodes.length; j++ ) {

  	  cp = cNodes[j] ;
          cn = cp.nodeName ;

	  debug( cn, 3 ) ;

	  if ( cn == "updatecell" ) {

	    cpn = cp.childNodes ;
 	    x_text = " " ;  // In case it is not there

	    for ( var k=0; k<cpn.length; k++ ) {

  	      gp = cpn[k] ;
	      gn = gp.nodeName ;
	      gpn = gp.childNodes ;
	      if ( gpn.length > 0 )
	        gv = gpn[0].nodeValue ;
	      else
 	        gv = "" ;

	      if ( gn == "row" )
	        x_row = parseInt(gv) ;
	      else if ( gn == "col" )
	        x_col = parseInt(gv) ;
	      else if ( gn == "colspan" )
	        x_colspan = parseInt(gv) ;
	      else if ( gn == "rendition" )
	        x_rendition = parseInt(gv) ;
	      else if ( gn == "graphics" )
	        x_graphics = parseInt(gv) ;
	      else if ( gn == "flags3" )
	        x_flags3 = parseInt(gv);
	      else if ( gn == "text" )
	        x_text = gv ;
	 
	      //output += gn + "=" + gv + "\n" ;

	    }

 	    // Call updatecell
	    focusOBJ.updatecell (  
			x_row, x_col, x_colspan,
		  	x_rendition, x_flags3,
		  	focusOBJ.rv(),
 	    		x_graphics,
		  	x_text ) ;
          }
 
  	  else if ( cn == "scrollup" || cn == "scrolldown" ) {

	    cpn = cp.childNodes ;

	    for ( var k=0; k<cpn.length; k++ ) {

  	      gp = cpn[k] ;
	      gn = gp.nodeName ;
	      gpn = gp.childNodes ;
	      if ( gpn.length > 0 )
  	        gv = gpn[0].nodeValue ;
	      else
	        gv = "" ;

	      if ( gn == "startrow" )
	        x_startrow = parseInt(gv) ;
	      else if ( gn == "endrow" )
	        x_endrow = parseInt(gv) ;
	 

	    }
	    debug(cn+" "+x_startrow+" "+x_endrow,3);
	    if ( cn == "scrollup" )
	      focusOBJ.scrollup ( x_startrow, x_endrow ) ;
    	    else
	      focusOBJ.scrolldown ( x_startrow, x_endrow ) ;
	  }
        }
      }
    }
  }


  if ( focusOBJ && focusOBJ.hasKeys() ) focusOBJ.startFlash() ;

  // Restore focusOBJ to where the user has last used his keyboard.
  if ( keyOBJ != null ) focusOBJ = keyOBJ ;

  doCheckup = true ;
}

function vtDisconnect() 
{
  // Point to next available request object
  doPolling = false ;
  nextRequest() ;
  var xmldata = 
    "<?xml version='1.0' encoding='UTF-8'?>"+
    "<xmldata><format>GET</format></xmldata>" ;
  ajaxRequest.setSuccessHandler ( 'disHandler' ) ;
  ajaxRequest.setTimeoutHandler ( 'disTimeout' ) ;
  ajaxRequest.setName ( '$GET' ) ;
  ajaxRequest.loadXMLDocAsync( "POST","/DISCONNECT_VT", xmldata, commandTimeout ) ;
} 

function do_checkup(evt)
{
  if ( !doCheckup ) return ;

  debug('do_checkup',3 ) ;

  var getState1 = ajaxRequest1.getReadyState() ;
  var getName1 = ajaxRequest1.getName() ;
  debug ( 'Current state of (1) '+getName1+' is '+getState1, 3);

  var getState2 = ajaxRequest2.getReadyState() ;
  var getName2 = ajaxRequest2.getName() ;
  debug ( 'Current state of (2) '+getName2+' is '+getState2, 3);

  if ( (getState1 > 0 && getState1 < 4 ) || 
       (getState2 > 0 && getState2 < 4 ) ) return ;

  if ( checkBusy(true) ) return ;

  doPolling = true ;
  issueGet() ;
}

function checkBusy( resend ) 
{
  // Loop through all objects, see if there is something
  // to do, then send out a PUT request.
  //

  var fo ;
  for ( var fon in dashObject ) {

    debug("Checking "+fon,3);
 
    fo = dashObject[fon] ;

    if ( fo == null ) continue ;

    if ( resend ) {
      if ( fo.getKeyBuf() != "" ) {
        debug(fon+' resending key buf',3); 
        issuePut ( fon, fo.getKeyBuf(), "KEY" ) ;
        return true ;
      }

      if ( fo.getLineBuf() != "" ) {
        debug(fon+' resending line buf',3); 
        issuePut ( fon, fo.getLineBuf(), "PUT" ) ;
        return true ;
      }
    }

    if ( fo.loadKeys() ) {
      debug(fon+' sending new key buffer',3); 
      issuePut ( fon, fo.getKeyBuf(), "KEY" ) ;
      return true ;
    }

  }

  debug("Not busy",3);
  return false ;
}

function connectBob() {

  nextRequest() ;
  var xmldata = 
	"<?xml version='1.0' encoding='UTF-8'?>"+
	"<xmldata><user>" + sb_username + "</user></xmldata>" ;
  ajaxRequest.setSuccessHandler ( 'conHandler' ) ;
  ajaxRequest.setTimeoutHandler ( 'conTimeout' ) ;
  ajaxRequest.setName ( '$CONNECT' ) ;
  debug('Issuing CONNECT_BOB',2);
  ajaxRequest.loadXMLDocSync( "POST","/CONNECT_BOB", xmldata, connectTimeout ) ;

  return ;
}

function connectChat() {

  nextRequest() ;
  var xmldata = 
	"<?xml version='1.0' encoding='UTF-8'?>"+
	"<xmldata><user>" + sb_username + "</user></xmldata>" ;
  ajaxRequest.setSuccessHandler ( 'conHandler' ) ;
  ajaxRequest.setTimeoutHandler ( 'conTimeout' ) ;
  ajaxRequest.setName ( '$CONNECT' ) ;
  debug('Issuing CONNECT_CHAT',2);
  ajaxRequest.loadXMLDocSync( "POST","/CONNECT_CHAT", xmldata, connectTimeout ) ;

  return ;
}

/////////////////////////////////////////////////////////////
//
// INITIALIZATION
//

//////////////////////////////////////////////////////////////

function focusObjectWait ( fullPanelName )
{
  debug('focusObjectWait('+fullPanelName+')',3 );  
  pause ( 3000 ) ;
  focusObject( fullPanelName ) ;
  
}

function pause( iMilliseconds )
{
    var sDialogScript = 'window.setTimeout( function () { window.close(); }, ' + iMilliseconds + ');';
    window.showModalDialog('javascript:document.writeln ("<script>' + sDialogScript + '<' + '/script>")');
}

function focusObject ( fullPanelName )
{
  debug('focusObject('+fullPanelName+')',3 );

  // This is the object.  It could be static, it could be active.
  focusOBJ = dashObject[fullPanelName] ;

  // This is the panel (DIV) for the object
  // It is further encased in a frame_<panelName> which
  // is appended to the dashboard DIV
  var panelOBJ = getRawObject(fullPanelName) ;

  // There may or may not be additional contents
  var contents = null ;

  // What kind of object is it?
  var tok = fullPanelName.split('_');
  var panelType = tok[0] ;
  var panelName = tok[1] ;

  var isChat   = ( panelType == "chat" ) ;
  var isTelnet = ( panelType == "telnet" ) ;
  var isUser   = ( panelName == sb_username ) ;
  var isKey    =  isTelnet || ( isChat && isUser ) ; 

  //if ( isTelnet ) debugLevel = 3 ;

  if ( !panelOBJ ) { 

    debug('no panelOBJ , calling makePanel',2);

    // This makes DIV objects frame_<panelName> and 
    // <panelType>_<panelName> (aka <fullPanelName>)
    makePanel ( fullPanelName ) ;

    panelOBJ = getRawObject(fullPanelName) ;
  }

  if ( panelOBJ ) {

    debug('panelOBJ panel found',3);

    // If the object hasn't been created, do that now.
    if ( focusOBJ == null )  {

      //debug('no focusOBJ, making new one',2);

      if ( isChat ) { 
        focusOBJ = new VTobject ( panelName, panelType, 3, 20 ) ;
	contents = focusOBJ.makeObject() ;
      }
      else if ( isTelnet ) {
        focusOBJ = new VTobject ( panelName, panelType, 24, 132 ) ;
	contents = focusOBJ.makeObject() ;
      }
      else {
        focusOBJ = new GENobject ( panelName, panelType ) ;
	contents = focusOBJ.makeObject() ;
      }
      debug('Cacheing '+focusOBJ.getName(), 3 ) ;
      dashObject[fullPanelName] = focusOBJ ;
    }
    //else {
    //  contents = focusOBJ.frame() ;
    //}

    // Objects can contain static or dynamic contents. 
    //
    // eg: fullPanelName = "chat_guest"
    //
    //  <div id="dashboard">
    //	  <div id="frame_guest">
    //	    <div id="chat_guest">  <--panelOBJ
    //	      <div id="contents_guest">
    //
    // The contents is the DIV container that contains
    // the panel contents.  

    var contentsOBJ = getRawObject('contents_'+panelName) ;

    if ( contentsOBJ && contents ) {

      child = contentsOBJ.firstChild ;

      if ( child )
        contentsOBJ.replaceChild( contents, child ) ; 
      else
        contentsOBJ.appendChild( contents ) ;

    }
  }

  focusOBJ.setFocus() ;

  return focusOBJ ;   
}

function makePanel( fullPanelName )
{
  debug("makePanel("+fullPanelName+")",3  );

  // Create a dynamic panel.
  //
  // Every panel is uniquely identified by three things:
  //
  //	Its frame   :  id = frame_<panelName>
  //	Its object  :  id = <panelType>_<panelName>
  //	Its content :  id = contents_<panelName>
  //
  // panelName is an unique database descriptor on the server side.
  // panelType tells us what type of panel it will become.
  // <panelType>_<panelName> is the fullPanelName
  //
  //    Example:
  //
  //		panel_console
  //		panel_links
  //		chat_bergsma
  //		telnet_localhost
  //		pf_outlook
  //
  // where the first part of the panelName is the panelType
  //
  //	panel, chat, object, telnet, pf	
  //
  // Before the panel is rendered, its size and position
  // must be known. This is the first ajax call, the URL target is "CONFIG".
  // The arguments passed are panelName and panelType, in an XML stream.
  //
  // An XML stream is returned that tells the x,y,w,h,title, etc
  // of the panel. 
  //
  // The descriptor tells the panel-maker (this javascript function)
  // the following information
  //
  //    - the id
  //    - the title
  //    - the position
  //    - the size
  //    - (optional) the name of an action to fetch HTML contents ne
  //    - (optional) the name of a hyperscript to load
  //
  // Get information about the panel. 

  // Point to next available request object
  nextRequest() ;

  // While we get panel info, we disable polling.
  disablePollingForMP( fullPanelName ) ;
  // Sometimes we just cannot do it.
  if ( delayedMP ) return ;

  var tokens = fullPanelName.split('_') ;
  var panelType = tokens[0];
  var panelName = tokens[1] ;
  var xmldata = "<?xml version='1.0' encoding='UTF-8'?>" +
		"<xmldata><panelName>" + panelName + 
		"</panelName><panelType>" + panelType + 
		"</panelType></xmldata>" ;

  // Our panel making call is SYNCHRONOUS, ie: we wait for it.
  ajaxRequest.setSuccessHandler ( 'configSuccess' ) ;
  ajaxRequest.setTimeoutHandler ( 'configTimeout' ) ;
  ajaxRequest.setName ( fullPanelName ) ;
  ajaxRequest.loadXMLDocSync( "POST","/CONFIG", xmldata, commandTimeout ) ;
  return ;
}

function configTimeout ( req )
{
  debug( "config timeout",2  );
}

function configSuccess( req )
{
  debug( "SUCCESS: configSuccess()",3  );
  var xmldoc    = req.responseXML()  ;

  // The panelName gets refetched here, but its ALWAYS the
  // same name as when we made the AJAX call (it gets copied)

  panelName     = getElementTextNS("","panelName" , xmldoc, 0) ;
  debug( "panelName="+panelName,3  );

  if ( panelName == "n/a" ) {
    // Communication HTTP protocol problem.
    // Wait a second before re-enabling GET requests.
    window.setTimeout('enablePolling()',delayInterval) ;
    return ;
  }

  var panelType = getElementTextNS("","panelType" , xmldoc, 0) ;
  var title     = getElementTextNS("","panelTitle" , xmldoc, 0) ;
  var x         = parseInt( getElementTextNS("","panelLeft" , xmldoc, 0) ) ;
  var y         = parseInt( getElementTextNS("","panelTop" , xmldoc, 0) ) ;
  var w         = parseInt( getElementTextNS("","panelWidth" , xmldoc, 0) ) ;
  var h         = parseInt( getElementTextNS("","panelHeight" , xmldoc, 0) );
  var action    = getElementTextNS("","panelAction" , xmldoc, 0) ;
  var hs        = getElementTextNS("","panelHS" , xmldoc, 0) ;

  var fullPanelName = panelType + "_" + panelName ;

  // Make panel, or locate it.

  var myDIVpanel = null ;

  var panelId = getRawObject ( fullPanelName ) ;

  if ( !panelId ) {
      
    // Panel does not exist, create it.
    debug("creating panel "+fullPanelName ,3 );

    panelId=document.createElement("div");

    panelId.style.top = (y + dashboardOffsetTop) + "px" ;
    panelId.style.left = (x + dashboardOffsetLeft) + "px" ;
    panelId.style.width = (w + 20) + "px" ;
    panelId.style.position = "absolute" ;

    // PANEL IDENTIFIER
    if ( panelType == "chat" || panelType == "object" ) {
      panelId.setAttribute( "class", "chatPanel" ) ;  
      panelId.setAttribute( "className", "chatPanel" ) ;  
    }
    else {
      panelId.setAttribute( "class", "appPanel" ) ;  
      panelId.setAttribute( "className", "appPanel" ) ;  
    }
    panelId.setAttribute( "id", "frame_"+panelName ) ;  

    // PANEL HEADER
    if ( panelType != "chat" && panelType != "object" ) {

      // Regular panel
      myDIV2=document.createElement("div");
      myDIV2.setAttribute( "class", "panelHeader" ) ;
      myDIV2.setAttribute( "className", "panelHeader" ) ;

      myA=document.createElement("a");
      myA.setAttribute( "name","drag_"+fullPanelName ) ;
      myA.setAttribute( "href", "javascript:void(0);" ) ;
      myA.setAttribute( "class", "panelName" ) ;
      myA.setAttribute( "className", "panelName" ) ;

      myTEXT  = document.createTextNode( title );
      myA.appendChild(myTEXT);
      myDIV2.appendChild(myA);

      myIMG=document.createElement("img");
      myIMG.setAttribute( "name",fullPanelName ) ;
      myIMG.setAttribute( "id","showhide_"+panelName ) ;
      myIMG.setAttribute( "class", "panelHide" ) ;
      myIMG.setAttribute( "className", "panelHide" ) ;
      myIMG.setAttribute( "src", "images/hide.gif" ) ;
      myIMG.setAttribute( "alt", "hide panel" ) ;
      myIMG.onclick = hidePanelEvt ;
      myDIV2.appendChild(myIMG);

      myIMG=document.createElement("img");
      myIMG.setAttribute( "name","frame_"+panelName ) ;
      myIMG.setAttribute( "id","close_"+panelName ) ;
      myIMG.setAttribute( "class", "panelClose" ) ;
      myIMG.setAttribute( "className", "panelClose" ) ;
      myIMG.setAttribute( "src", "images/close.gif" ) ;
      myIMG.setAttribute( "alt", "close panel" ) ;
      myIMG.onclick = closePanelEvt ;
      myDIV2.appendChild(myIMG);

      myDIV3=document.createElement("div");
      myDIV3.setAttribute( "class", "panelRightEdge" ) ;
      myDIV3.setAttribute( "className", "panelRightEdge" ) ;

      myDIV2.appendChild(myDIV3) ;
      panelId.appendChild ( myDIV2 ) ;
    }
    else if ( panelName == sb_username )  {

      // Owner's window
      myDIV2=document.createElement("div");
      myDIV2.setAttribute( "class", "objectHeader" ) ;
      myDIV2.setAttribute( "className", "objectHeader" ) ;
      myIMG=document.createElement("img");
      myIMG.setAttribute( "name",fullPanelName ) ;
      myIMG.setAttribute( "id","showhide_"+panelName ) ;
      myIMG.setAttribute( "class", "panelHide" ) ;
      myIMG.setAttribute( "className", "panelHide" ) ;
      myIMG.setAttribute( "src", "images/hide.gif" ) ;
      myIMG.setAttribute( "alt", "hide panel" ) ;
      myIMG.onclick = hidePanelEvt ;
      myDIV2.appendChild(myIMG);

      myIMG=document.createElement("img");
      myIMG.setAttribute( "name","frame_"+panelName ) ;
      myIMG.setAttribute( "id","close_"+panelName ) ;
      myIMG.setAttribute( "class", "panelClose" ) ;
      myIMG.setAttribute( "className", "panelClose" ) ;
      myIMG.setAttribute( "src", "images/close.gif" ) ;
      myIMG.setAttribute( "alt", "close panel" ) ;
      myIMG.onclick = closePanelEvt ;
      myDIV2.appendChild(myIMG);
      panelId.appendChild ( myDIV2 ) ;

    }

    // PANEL CONTENTS
    myDIVpanel=document.createElement("div");
    myDIVpanel.setAttribute( "id",fullPanelName ) ;
    myDIVpanel.setAttribute( "class","content" ) ;
    myDIVpanel.setAttribute( "className","content" ) ;

    if ( panelType != "chat" && panelType != "object" ) {
      // Regular panel
      myDIV2=document.createElement("div");
      myDIV2.setAttribute( "class", "panelBody" ) ;
      myDIV2.setAttribute( "className", "panelBody" ) ;
      myDIV3=document.createElement("div");
      myDIV3.setAttribute( "class", "panelRightEdge" ) ;
      myDIV3.setAttribute( "className", "panelRightEdge" ) ;
      myDIV3.appendChild(myDIVpanel);
      myDIV2.appendChild(myDIV3);
    }
    else {
      myDIV2=document.createElement("div");
      myDIV2.setAttribute( "class", "chatBody" ) ;
      myDIV2.setAttribute( "className", "chatBody" ) ;
      myDIV2.appendChild(myDIVpanel);
    }

    panelId.appendChild(myDIV2) ;

    // PANEL FOOTER
    if ( panelType != "chat" && panelType != "object" ) {

      // Regular panel.
      myDIV2=document.createElement("div");
      myDIV2.setAttribute( "class", "panelFooter" ) ;
      myDIV2.setAttribute( "className", "panelFooter" ) ;

      myDIV3=document.createElement("div");
      myDIV3.setAttribute( "class", "panelRightEdge" ) ;
      myDIV3.setAttribute( "className", "panelRightEdge" ) ;
      myDIV2.appendChild(myDIV3);
      panelId.appendChild(myDIV2) ;
    }

    // Add it to the array.
    //panelArray.push ( panelName ) ;

    var dashId = getRawObject ( 'dashboard' ) ;
    dashId.appendChild ( panelId ) ;
  
    // Now load panel contents
    loadPanel ( panelName, panelType, action, hs ) ;
   
    // Wait some seconds before enabling
    // GET requests, give time for images to load.
    // Perhaps a reliable onload handler can be put here,
    // but it must work with ALL browser types.
    // CURRENT: 9 seconds
    window.setTimeout('enablePolling()',delayInterval*3) ;
  }
  else {
  
    // Re-enable GET requests right away.
    enablePolling() ;
  }
}

function loadPanel( panelName, panelType, action, hs )
{
  debug( "loadPanel("+panelName+","+action+")",3  );
  var s = "<div>Blank for now</div>" ;

  // If action is defined, then get the 's' contents 
  if ( action && action != "" && action != "n/a" ) {

    var xmldata = "<?xml version='1.0' encoding='UTF-8'?>" +
    		"<xmldata><panelName>" + 
		panelName + "</panelName></xmldata>" ;
    nextRequest() ;
    ajaxRequest.setTimeoutHandler ( 'actionTimeout' ) ;
    ajaxRequest.setSuccessHandler ( 'actionSuccess' ) ;
    ajaxRequest.setName ( panelType+"_"+panelName ) ;
    ajaxRequest.loadXMLDocSync( "POST","/"+action, xmldata, commandTimeout) ; 
  }
 
  // If there's a hyperscript attachment, load it now.
  if ( hs && hs != "" && hs != "n/a" ) {
    load_brains ( hs, deployMethod ) ;
  }
  else if ( panelName == "hsdom" ) {

    // This special litte panel's purpose is to launch the HS-DOM.
    // either via activeX or JAVA.
    //
    if ( !isDOM_HS ) {
      loadHSDOM() ;
      isDOM_HS = 1 ;
    }
  }
}


function loadHSDOM( )
{
  debug( "Loading HS-DOM", 2  );

  var xmldata = 
	"<?xml version='1.0' encoding='UTF-8'?>"+
	"<xmldata><tag>hsdom</tag></xmldata>" ;
  
  ajaxRequest.setTimeoutHandler ( 'HSDOMtimeout' ) ;
  ajaxRequest.setSuccessHandler ( 'HSDOMsuccess' ) ;
  ajaxRequest.setName ( 'hsdom' ) ;
  ajaxRequest.loadXMLDocSync( "POST","/GET_HSDOM", xmldata, commandTimeout) ;
}

function HSDOMtimeout ( request )
{
  debug('Http Request timeout on '+request.getName(), 2 ) ;
}


function HSDOMsuccess ( req ) 
{
  debug( 'action success',3 ) ;
  var s = req.responseText() ;

  var fullPanelName = req.getName() ;

  // Locate panel contents.
  var myDIVpanel = getRawObject ( fullPanelName ) ;

  // Update the contents
  myDIVpanel.innerHTML = s ;

  return ;
}

function actionTimeout ( request )
{
  debug('action timeout',2 ) ;
}

function actionSuccess ( req ) 
{
  debug( 'action success',3 ) ;
  var s = req.responseText() ;

  var fullPanelName = req.getName() ;

  // Locate panel contents.
  var myDIVpanel = getRawObject ( fullPanelName ) ;

  // Update the contents
  myDIVpanel.innerHTML = s ;

  focusObject ( fullPanelName ) ;

  return ;
}

function addPanel( panelName, element )
{
  // Add it to the array.
  panelArray.push ( panelName ) ;

  var dashId = getRawObject ( 'dashboard' ) ;
  dashId.appendChild ( element ) ;
}

function makeChat( )
{
   connectChat() ;
} 

function makeTelnet()
{
  var identifier = "telnet" ;
  focusObject ( "telnet_"+identifier ) ;
} 

// Turn selected element on
function showPanelEvt(evt) 
{
  evt = (evt) ? evt : event;
  var target = (evt.target) ? evt.target : evt.srcElement;
  if ( target ) {
    target.onclick = hidePanelEvt ;
    target.src = "/images/hide.gif" ;
    var panel = getRawObject ( target.name ) ; 
    showElement ( panel ) ;
  }
}

function showPanel( panelName )
{
  var target = getRawObject ( "showhide_"+panelName ) ;
  if ( target ) {
    target.onclick = hidePanelEvt ;
    target.src = "/images/hide.gif" ;
    var panel = getRawObject ( target.name ) ; 
    showElement ( panel ) ;
  }
}

function hidePanelEvt(evt) 
{
  evt = (evt) ? evt : event;
  var target = (evt.target) ? evt.target : evt.srcElement;
  if ( target ) {
    target.onclick = showPanelEvt ;
    target.src = "/images/open.gif" ;
    var panel = getRawObject ( target.name ) ;
    hideElement ( panel ) ;
  }
}

function hidePanel( panelName )
{
  var target = getRawObject ( "showhide_"+panelName ) ;
  if ( target ) {
    target.onclick = showPanelEvt ;
    target.src = "/images/open.gif" ;
    var panel = getRawObject ( target.name ) ; 
    hideElement ( panel ) ;
  }
}

function closePanelEvt( evt )
{
  evt = (evt) ? evt : event;
  var target = (evt.target) ? evt.target : evt.srcElement;
  if ( target ) {
    debug("Closing panel "+target.name,0);
    closePanel ( target.name ) ;
  }
}

function closePanel( panelName )
{
  var panel = getRawObject ( panelName ) ;
  if ( panel ) {
    var dashId = getRawObject ( 'dashboard' ) ;
    var removed = dashId.removeChild ( panel ) ;
    //////dashObject[ panelName ] = null ;///////////////
  }
}

/////////////////////////////////////////////////////////////
//
// GEN OBJECT DEFINITION
//
//////////////////////////////////////////////////////////////

function GENobject ( panelName, panelType )
{
  this.gen_name = panelName ;
  this.gen_type = panelType ;
  this.gen_frame = null ;

  debug( 'new GEN object '+panelType+'_'+panelName,3);

  /*************************************************************
   *  Object functions 
   *************************************************************/

  GENobject.prototype.getName = function()
  {
    return this.gen_type+"_"+this.gen_name ;
  } ;

  GENobject.prototype.getFrame = function()
  {
    return "frame_" + this.gen_name ;
  } ;

  GENobject.prototype.frame = function()
  {
    return this.gen_frame ;
  }

  GENobject.prototype.hasKeys = function () 
  {
    return false
  } ;

  GENobject.prototype.isChat = function () 
  {
    return false ;
  } ;

  GENobject.prototype.makeObject = function() 
  {
    // The GEN object contains several components 

    debug ( 'Making GEN object', 3 ) ;

    // Add in the controls
    var gen_controls_table = this.createGENcontrols() ;

    // Put everything together in a frame

    //alert ( "Assembing frame "+this.vt_name);
    var gen_f = document.createElement("DIV");

    gen_f.setAttribute( "id","gen_frame_"+this.gen_name);
    gen_f.setAttribute( "class","genframe");
    gen_f.setAttribute( "className","genframe");

    myDIV=document.createElement("DIV");
    myDIV.setAttribute( "class","GENcontrols");
    myDIV.setAttribute( "className","GENcontrols");
    myDIV.appendChild( gen_controls_table ) ;
    gen_f.appendChild( myDIV ) ;

    this.gen_frame = gen_f ;
    return gen_f ;

  } ;

  GENobject.prototype.createGENcontrols = function ( )
  {
    //alert ( "Creating control "+this.vt_name);

    var gen_controls_table = document.createElement("TABLE");
    gen_controls_table.setAttribute( "border","0");
    gen_controls_table.setAttribute( "cellSpacing","0");
    gen_controls_table.setAttribute( "cellPadding","2");

    myTBODY=document.createElement("TBODY");
    myTR=document.createElement("TR");
    myTD=document.createElement("TD");
    myTEXT  = document.createTextNode( this.gen_name );
    myTD.appendChild(myTEXT);
    myTR.appendChild(myTD);
    myTBODY.appendChild(myTR);
    gen_controls_table.appendChild(myTBODY);
    return gen_controls_table ;
  };


  GENobject.prototype.getKeyBuf = function()
  {
    return "" ;
  } ;

  GENobject.prototype.loadKeys = function ()
  {
    return false ;
  };

  GENobject.prototype.setFocus = function()
  {
    return false ;
  } ;

  GENobject.prototype.getLineBuf = function()
  {
    return "" ;
  } ;

  return ;

} ; // End of GEN object