//
// Monitor scrolling in the web page, by setting a ScrollSpy
//
// Inspired by & based on:
//
//   "Drifting Layers:  Keeping Important Elements Visible"
//   -- Michael Bostock
//      http://developer.netscape.com/docs/technote/dynhtml/drift/
//
// By Willem Broekema, <willem@pastelhorn.com>
// Visit http://pastelhorn.com/project/js/scrollspy/ for more info and latest
// release.
//
// version 0.9.1, January 13 2000:
//  -  Added conditional code for Opera to work around "Anchor - setInterval bug"
//    (see http://pastelhorn.com/project/js/scrollspy/operabug).
//
// version 0.9.0 -- January 5 2000:
//  - First release.
//


// Part of browser detection script copied from 
// http://developer.netscape.com/docs/examples/javascript/browser_type.html
//
// This following Opera detection code is used to work around the
// "Anchor - setInterval" bug in (at least) Opera 5 
// -- see http://pastelhorn.com/project/js/scrollspy/operabug

var agt = navigator.userAgent.toLowerCase();
var isOperaSpy = (agt.indexOf("opera") != -1) ? 1 : 0;

/// the following browser detection code is not currently used, but appears
/// to be working:
//
// var isNav4Spy = (document.layers && !isOperaSpy) ? 1 : 0;
// var isIE4Spy  = (document.all && !isOperaSpy) ? 1 : 0;
// var isMozSpy  = (document.getElementById && !(isNav4Spy || isIE4Spy || isOperaSpy)) ? 1 : 0;
// var isOpera5IE5Spy = (document.all && (window.pageYOffset || window.pageYOffset == 0) ) ? 1 : 0;
//
// window.alert('op: ' + isOperaSpy + '; nav4: ' + isNav4Spy + '; isIE4: ' + isIE4Spy + '; moz: ' + isMozSpy + '; O5IE5: ' + isOpera5IE5Spy);

//
/// If (isMozSpy == 1), assume it's one of:
///  - Mozilla;
///  - Opera 5, set to be identified as 'Mozilla X',
///    with X one of (5.0; 4.76; 3.0).
//
/// If (isOpera5IE5Spy == 1), then assume browser is Opera set to
/// identify as 'MSIE 5' although it does not support all properties of it
//



function scrollSpy(theFunction) {

//
// First, set window.RANDOMNAME to this Spy object, so the outside world
// can refer to it.
//
// Although ugly, it's needed, if we want "setInterval()" to apply a method
// on our object:  when using "setInterval("this...", ..)", the
// "this" will refer to the window, because that's the object running
// the function "setInterval".
//
// Another solution would be, passing the object's name as parameter to
// the constructor:
//
//   S = new scrollSpy('S', func)
//
// and use the first parameter to build the "setInterval()" command line.
//

  var NameOfThisSpy = generateSpyInternalName();
  
  eval('window.' + NameOfThisSpy + ' = this;'); // window.RANDOMNAME = <this_spy&gt;
  eval('this.name = "' + NameOfThisSpy + '";'); // <this_spy>.name = "RANDOMNAME"

  this.changeFunction = theFunction;
  this.intervalTime = 200;   // by default 200 milliseconds
  this.enabled = 0;
  this.monitor = monitorScrolling;

  this.getWindowYOffset = getWindowYOffsetSpy;
  this.prevWindowYOffset = 0;

 /// public interface:  

  this.start = startSpy;
  this.stop = stopSpy;
  this.isRunning = isRunningSpy;
  
  this.getIntervalTime = getIntervalTimeSpy;
  this.setIntervalTime = setIntervalTimeSpy;

 /////
}



function startSpy() {
  if (!this.enabled) { // not already running?

    var cmdstring = 'window.' + this.name + '.monitor()';
    
    if (!isOperaSpy)
      this.interval = window.setInterval( cmdstring, this.intervalTime );
    else // work around bug
      this.interval = window.setTimeout( cmdstring, this.intervalTime );

    this.enabled = 1;
  }
}

function stopSpy() {
  if (this.enabled) { // really running?
    window.clearInterval(this.interval);
    this.enabled = 0;
  }
}

function isRunningSpy() {
  return this.enabled;
}

    

function getIntervalTimeSpy() {
  return this.intervalTime;
}

function setIntervalTimeSpy(newValue) {
  var wasRunning = (this.enabled) ? 1 : 0;
  this.stop();
  this.intervalTime = newValue;
  if (wasRunning)
    this.start();
}



function getWindowYOffsetSpy() {
  if ( window.pageYOffset || window.pageYOffset == 0 )
    return window.pageYOffset;
  if ( document.body.scrollTop || document.body.scrollTop == 0 )
    return document.body.scrollTop;

// // Testing for capacity is better then testing for browser version,
// // but assuming the browser is one of the ones we check for, an
// // equivalent version is:
//
//  if (isNav4Spy || isMozSpy || isOperaSpy)
//    return window.pageYOffset;
//  if (isIE4Spy)
//    return document.body.scrollTop;

}


  
function monitorScrolling() {

  var newWinYOffset = getWindowYOffsetSpy();
  var Scrolled = (newWinYOffset != this.prevWindowYOffset);

  this.prevWindowYOffset = newWinYOffset;

  if (Scrolled)
    eval( 'this.changeFunction(' + newWinYOffset + ')' );

  if (isOperaSpy) {  // work around bug
    var cmdstring = 'window.' + this.name + '.monitor()';
    this.interval = window.setTimeout( cmdstring, this.intervalTime);
  }
    
}



function generateSpyInternalName() {
  var now = new Date();
  var rand = Math.floor(  1000000 * Math.random(now.getTime())  );
  return ('spy' + rand + 's');
}

