//
// $Id: HSapi.js,v 1.3 2007-03-26 21:46:59 bergsma Exp $
//
// $Log: HSapi.js,v $
// Revision 1.3  2007-03-26 21:46:59  bergsma
// Abinition web site 2007
//
// Revision 1.39  2006-08-29 23:50:08  bergsma
// no message
//
// Revision 1.38  2005/12/20 06:36:25  bergsma
// *** empty log message ***
//
// Revision 1.36  2005/12/16 00:17:51  bergsma
// *** empty log message ***
//
// Revision 1.35  2005/11/25 03:15:34  bergsma
// *** empty log message ***
//
// Revision 1.33  2005/11/14 17:41:05  bergsma
// no message
//
// Revision 1.32  2005/11/06 16:50:29  bergsma
// no message
//
// Revision 1.31  2005/10/20 00:29:30  bergsma
// no message
//
//
// Revision 1.6  2005/06/23 01:47:12  bergsma
// Dashboard 2005
//
// Revision 1.1  2005/02/13 01:15:40  bergsma
// Relocated to dist/webpickle/dashboard/js
//
// Revision 1.2  2005/02/06 18:27:54  jbergsma
// Functions to interface HyperScript (i.e. WebPickle) with JavaScript for the dashboard application.
//
//

// GLOBAL VARIABLES
var isBootStrapped = false ;
var isBootStrapping = false ;
var isLoaded = false ;
var isLoading = false ;
var ab = null ;
var isJava = 0 ;
var isActiveX = 0 ;
var deploy = "" ;
var maxLoads = 10 ;
var maxBoots = 5 ;
var bootIntervalID = null ;
var loadIntervalID = null ;
var nodeName = "" ;
var server = "" ;
var portnum = "" ;
var target = "" ; 

///////////////////////////////////////////////////////////////////
//
// BOOTSTRAP SECTION
//
///////////////////////////////////////////////////////////////////

// FUNCTION TO SET THE HANDLE TO HYPERSCRIPT
function setAb( fn )
{
  if ( ab != null ) return ab ;
  ab = document.HyperScript2 ;
  if ( ab == null )
    alert ( fn+ ": No HyperScript for deploy method '"+deploy+"'" ) ; 
  return ab ;
}

// BOOTSTRAP - DO THIS BEFORE LOAD_BRAINS!!!
function bootstrap ( dm, nn )
{
  //alert ( "bootstrap" );
  deploy = dm ;
  nodeName = nn ;

  server = location.host ;
  portnum = location.port ;
  if ( portnum == "" ) portnum = 80 ;
  target = "/" + nn + ".hyp" ;

  isJava = ( deploy == "java" ) ;
  isActiveX = ( deploy == "activex" );

  // We always invoke bootstrap under a repeating timer.  Try every second.
  if ( bootIntervalID != null ) window.clearInterval(bootIntervalID) ;
  bootIntervalID = window.setInterval("bootstrap2()",1000) ;
}

function bootstrap2 ( )
{
  //alert("bootstrap2");

  // Don't try more than maxBoot times
  maxBoots-- ;

  // If there are no objects loaded yet, return and
  // wait for the timer to go off again.

  // For the ActiveX case, there'll be 2 objects.
  if ( document.applets.length == 0 && maxBoots > 0 ) return ;

  // We think we've got HyperScript. Cancel the timer.
  if ( bootIntervalID != null ) {
    window.clearInterval ( bootIntervalID ) ;
    bootIntervalID = null ;
  }
  
  // If we exceeded our timer, then fail. 
  if ( maxBoots <= 0 ) {
     alert ( "Failed to bootstrap HyperScript2" ) ;
     if ( loadIntervalID != null ) {
       window.clearInterval ( loadIntervalID ) ;
       loadIntervalID = null ;
     }
     return ;
  }

  // Otherwise, onto booting.
  bootstrap3() ;
}

function bootstrap3()
{
  //alert ( "Bootstrap3 "+deploy ) ;

  // Make sure some other thread isn't doing the work.
  if ( isBootStrapping ) return ;

  // Set flag to indicate we are booting
  isBootStrapping = true ;

  // Init the DHTML
  initDHTMLAPI() ;

  // For activeX we need a console.
  if ( isActiveX ) openconsole();
  
  var httpRequest = new HttpXMLRequest( '','' ) ;
  httpRequest.loadXMLDocSync( "GET","/bootstrap.hyp","",3000) ;
  var s = httpRequest.responseText() ;


  // Locate the HyperScript object
  if ( setAb("Bootstrap") == null ) return ;

  // Load the bootstrap part of the HyperScript program
  var ret = ab.Parse( s ) ;
  if ( typeof(ret) != "undefined" && ret != "$ACK" ) {
    var e = "Bootstrap: Failed to parse brains, reason is " + ret ;
    alert ( e );
    return ;
  }

  // Decide which loopback to use for communication
  // between JAVA and HYPERSCRIPT
  // We choose a random localhost port
  var a = Math.round(Math.random() * 124) ;
  var b = Math.round(Math.random() * 124) ;
  var c = Math.round(Math.random() * 124) ;
  var loopbackAddr = 127 + "." + a + "." + b + "." + c ;
  var loopbackPort = 8088 ;

  // Put HS in idle mode, awaiting requests.
  var bootstrap = 'BOOTSTRAP("' + 
			loopbackAddr + '",' +
			loopbackPort + '); idle();' ;

  //alert (bootstrap );
  ret = ab.Parse ( bootstrap ) ;
   if ( typeof(ret) != "undefined" && ret != "$ACK" ) {
    var e = "Bootstrap: Failed to idle(), reason is " + ret ;
    alert ( e );
    return ;
  }

  // ActiveX uses the IE mailbox to send requests to 
  // HyperScript.  JAVA uses a loopback connection,
  // which must be established first.
  if ( isJava ) {
    var ret = ab.openSocketStream(loopbackAddr,loopbackPort);
    if ( ret != "$ACK" ) {
      var e = "Failed to connect hyperscript, reason is " + ret ;
      alert ( e );
    }
  }

  // Set flag to indicate we are done bootstrapping
  isBootStrapping = false ;
  isBootStrapped = true ;

  if ( !isLoading ) {
    // For netscape / mozilla / firefox, the load_brains() may never
    // get underway, so we give it a little shove.
    //alert ( "Load brains not happening, kicking");
    if ( loadIntervalID != null ) window.clearInterval(loadIntervalID) ;
    loadIntervalID = window.setInterval("load_brains2()",3000) ;
  }
}

// LOAD_BRAINS - do this after BOOTSTRAP!!
function load_brains( dm, nn )
{
  //alert ( "load_brains");
  deploy = dm ;
  nodeName = nn ;
  server = location.host ;
  portnum = location.port ;
  if ( portnum == "" ) portnum = 80 ;
  target = "/" + nn + ".hyp" ;  

  isJava = ( deploy == "java" ) ;
  isActiveX = ( deploy == "activex" );

  // We always invoke load_brains under a repeating timer. 
  // Try every 3 seconds, give time for bootstrapping to complete.
  if ( loadIntervalID != null ) window.clearInterval(loadIntervalID) ;
  loadIntervalID = window.setInterval("load_brains2()",3000) ;
}

function load_brains2 () 
{
  //alert("load_brains2");

  // Don't try more than maxBoot times
  maxLoads-- ;

  // If we have not completed bootstrapping,
  // then we cannot proceed
  if ( !isBootStrapped ) {
    // We can wait a bit.
    if ( maxLoads > 0 ) return ;
  }
   
  // We might be ok, cancel timer 
  if ( loadIntervalID != null ) {
    window.clearInterval ( loadIntervalID ) ;
    loadIntervalID = null ;
  }

  if ( maxLoads <= 0 ) {
     alert ( "Failed to load brains for HyperScript2 " ) ;
     return ;
  }

  // Do the real loading of brains
  load_brains3() ;
}

function load_brains3()
{
  // Make sure some other thread isn't doing the work.
  if ( isLoading ) return ;

  //alert ( "load_brains3" ) ;

  if ( !isBootStrapped ) {
    // In case we have not bootstrapped.
    alert ( "Bootstrap not happening, kicking");
    isBootStrapping = false ;
    if ( bootIntervalID != null ) window.clearInterval(bootIntervalID) ;
    bootIntervalID = window.setInterval("bootstrap2()",1000) ;
    return ;
  }

  // Now we load 
  isLoading = true ;

  e = "Load '" + nodeName + "':" + "'" + server+ "':" + "'" + portnum+ "':" + "'" + target+ "'";

  if ( setAb("Load Brains") == null ) return ;

  if ( isActiveX ) openconsole() ;

  var cmd = 'LOAD_BRAINS("' + 
	    server   + '",' + 
	    portnum  + ',"' + 
	    target   + '","' + 
	    deploy   + '");' ;

  //alert( cmd ) ;
  ret = ab.Eval ( cmd ) ;
  if ( typeof(ret) != "undefined" && ret != "$ACK" ) {
    var e = "Load Brains: Failed to Eval(), reason is " + ret ;
    alert ( e );
    return ;
  }
  isLoading = false ;
  isLoaded = true ;
}

///////////////////////////////////////////////////////////////////
//
// HYPERSCRIPT INTERFACE
//
///////////////////////////////////////////////////////////////////


// HSPARSE is a front-end to calling ab.Parse, the
// way in which to get tokens into hyperscript when it
// is not in an idle state. Most often used at bootstrap,
// to load in the brains of the hyperscript program
function hsparse ( cmd )
{
  if ( setAb("Parse") == null ) return ;
  ret = ab.Parse( cmd ) ;
  if ( typeof(ret) != "undefined" && ret != "$ACK" ) {
    var e = "HSparse: Failed to Parse(), reason is " + ret ;
    alert ( e );
    return ;
  }
}

// HSEVAL is a front-end to calling ab.Eval, the 
// way in which to send program code to Hyperscript
// to evaluate.  For JAVA, its over the loopback, for
// ActiveX its through the mailslot.
function hseval ( cmd )
{
  if ( setAb("Eval") == null ) return ;
  ret = ab.Eval( cmd ) ;
  if ( typeof(ret) != "undefined" && ret != "$ACK" ) {
    var e = "HSeval: Failed to Eval(), reason is " + ret ;
    alert ( e );
    return ;
  }
}

// HSCALL is used by JAVASCRIPT, such as FORM elements,
// to CALL/INVOKE specific HyperScript method.
function hscall ( t, m, argument )
{
  var c = 'event("' + t + '#"+self(2),"' + m + '",{},' + argument + ');' ;
  //alert ( c ) ;
  hseval ( c ) ;
  // Return false so that the form won't submit.
  return false ; 
}

function hscall2 ( t, m, argument )
{
  var c = 'event("' + t + '#"+self(2),"' + m + '",{}, "' + argument + '" );' ;
  //alert ( c ) ;
  hseval ( c ) ;
  // Return false so that the form won't submit.
  return false ; 
}

function hsputs ( argument )
{
  var c = 'event( self(2), "' + "PUTS" + '",{}, "' + argument + '" );' ;
  //alert ( c ) ;
  hseval ( c ) ;
  // Return false so that the form won't submit.
  return false; 
}

// ACTIVEX FUNCTIONS
function openconsole()
{
  document.WebPickle.CreateListBox() ;
}

function writeconsole( message )
{
  document.WebPickle.Puts( message ) ;
}

///////////////////////////////////////////////////////////////////////
//
// DOM FUNCTIONS
//
///////////////////////////////////////////////////////////////////////

// Update the innerHTML of a node
function updateNode ( nodeName, htmlData )
{
  var DOMnode = document.getElementById(nodeName);
  if ( DOMnode ) DOMnode.innerHTML = htmlData ; 
}

// Update the innerHTML of a node
function appendTextToNode ( nodeName, text )
{
  var DOMnode = document.getElementById(nodeName);
  if ( DOMnode ) {
    var t = document.createTextNode(text);
    DOMnode.appendChild(t);
    var br = document.createElement("BR");
    DOMnode.appendChild(br);
  }
}

// Update a form element
function updateFormElement ( formName, element, value )
{
   if ( value == undefined ) value = '' ;
   document.forms[formName].elements[0].value = value ;
}
