/*   dw_scrollLayers    version date: Feb 2004    */

/*************************************************************************
  This code is from Dynamic Web Coding at http://www.dyn-web.com/
  Copyright 2001-4 by Sharon Paine 
  See Terms of Use at http://www.dyn-web.com/bus/terms.html
  regarding conditions under which you may use this code.
  This notice must be retained in the code as is!
*************************************************************************/

dw_scrollLayers = {};
dw_scrollLayer.speed = 100; // default speed for mouseover scrolling
//  constructor arguments: id of layer containing scrolling layers (clipped layer), id of layer to scroll, 
//	id of table or other element that scrolling content is nested in. 
//	ns6+/moz need that extra container to get width for horizontal scrolling.
//	(not needed for vertical scrolling)
function dw_scrollLayer(wnId, lyrId, cntId) {
  this.id = wnId; dw_scrollLayers[this.id] = this;
  this.animString = "dw_scrollLayers." + this.id;
  this.loadLayer(lyrId, cntId);
}

dw_scrollLayer.prototype.loadLayer = function(lyrId, cntId) {
  if (!document.getElementById) return;
  var wndo, lyr;
  if (this.lyrId) {
    lyr = document.getElementById(this.lyrId);
    lyr.style.visibility = "hidden";
  }
  lyr = document.getElementById(lyrId);
  wndo = document.getElementById(this.id);
  lyr.style.top = this.y = 0; lyr.style.left = this.x = 0;
  this.maxY = (lyr.offsetHeight - wndo.offsetHeight > 0)? lyr.offsetHeight - wndo.offsetHeight: 0;
  this.wd = cntId? document.getElementById(cntId).offsetWidth: lyr.offsetWidth;
  this.maxX = (this.wd - wndo.offsetWidth > 0)? this.wd - wndo.offsetWidth: 0;
  this.lyrId = lyrId; // hold id of currently visible layer
  lyr.style.visibility = "visible";
  this.on_load(); this.ready = true;
}

dw_scrollLayer.prototype.on_load = function() {}

dw_scrollLayer.prototype.shiftTo = function(lyr, x, y) {
  lyr.style.left = (this.x = x) + "px"; 
  lyr.style.top = (this.y = y) + "px";
}

// functions for onmouseover scrolling 
// algorithm for time-based scrolling from youngpup.net

// called onmouseover. arguments: direction (possible values: 'up', 'down', 'left', 'right')
// speed (optional) to override default speed (set in dw_scrollLayer.speed)
dw_scrollLayer.prototype.startScroll = function(dir, speed) {
  if (!this.ready) return; if (this.timerId) clearInterval(this.timerId);
  this.speed = speed || dw_scrollLayer.speed;
  this.lyr = document.getElementById(this.lyrId);
  if (dir == "up" || dir == "down") {
    this.xdir = 0; this.endX = parseInt(this.lyr.style.left);
    this.ydir = (dir == "down")? -1: 1; this.endY = (dir == "down")? -this.maxY: 0;
  } else if (dir == "right" || dir == "left") {
    this.ydir = 0; this.endY = parseInt(this.lyr.style.top);
    this.xdir = (dir == "right")? -1: 1; this.endX = (dir == "right")? -this.maxX: 0;
  } else {
    alert("Up, down, left, and right are the only scroll directions currently supported.");
    return; 
  }
  this.lastTime = ( new Date() ).getTime();
  this.on_scroll_start();  
  this.timerId = setInterval(this.animString + ".scroll()", 10); 
}

dw_scrollLayer.prototype.scroll = function() {
  var now = ( new Date() ).getTime();
  var x = this.x + this.xdir * (now - this.lastTime)/1000 * this.speed;
  var y = this.y + this.ydir * (now - this.lastTime)/1000 * this.speed;
  if ( ( this.xdir == -1 && x > -this.maxX ) || ( this.xdir == 1 && x < 0 ) || 
    ( this.ydir == -1 && y > -this.maxY ) || ( this.ydir == 1 && y < 0 ) ) {
    this.lastTime = now;
    this.shiftTo(this.lyr, x, y);
    this.on_scroll(x, y);
  } else {
    clearInterval(this.timerId); this.timerId = 0;
    this.shiftTo(this.lyr, this.endX, this.endY);
    this.on_scroll_end(this.endX, this.endY);
  }
}

dw_scrollLayer.prototype.stopScroll = function() {
  if (!this.ready) return;
  if (this.timerId) clearInterval(this.timerId);
  this.timerId = 0;  this.lyr = null;
}
  
dw_scrollLayer.prototype.on_scroll = function() {}
dw_scrollLayer.prototype.on_scroll_start = function() {}
dw_scrollLayer.prototype.on_scroll_end = function() {}
  
// remove layers from table for ns6+/mozilla (needed for scrolling inside tables)
function GeckoTableBugFix() {
  var i, wndo, holderId, holder, x, y;
	if ( navigator.userAgent.indexOf("Gecko") > -1 ) {
    dw_scrollLayer.hold = []; // holds id's of wndo and its container
    for (i=0; arguments[i]; i++) {
      if ( dw_scrollLayers[ arguments[i] ] ) {
        wndo = document.getElementById( arguments[i] );
        holderId = wndo.parentNode.id;
        holder = document.getElementById(holderId);
        document.body.appendChild( holder.removeChild(wndo) );
        wndo.style.zIndex = 1000;
        x = holder.offsetLeft; y = holder.offsetTop;
        wndo.style.left = x + "px"; wndo.style.top = y + "px";
        dw_scrollLayer.hold[i] = [ arguments[i], holderId ];
      }
    }
   window.addEventListener("resize", rePositionGecko, true);
  }
}

// ns6+/mozilla need to reposition layers onresize when scrolling inside tables.
function rePositionGecko() {
  var i, wndo, holder, x, y;
  if (dw_scrollLayer.hold) {
    for (i=0; dw_scrollLayer.hold[i]; i++) {
      wndo = document.getElementById( dw_scrollLayer.hold[i][0] );
      holder = document.getElementById( dw_scrollLayer.hold[i][1] );
      x = holder.offsetLeft; y = holder.offsetTop;
      wndo.style.left = x + "px"; wndo.style.top = y + "px";
    }
  }
}













/*************************************************************************
    dw_event (version date Feb 2004)
        
    This code is from Dynamic Web Coding at http://www.dyn-web.com/
    See Terms of Use at http://www.dyn-web.com/bus/terms.html
    regarding conditions under which you may use this code.
    This notice must be retained in the code as is!
*************************************************************************/

var dw_event = {
  
  add: function(obj, etype, fp, cap) {
    cap = cap || false;
    if (obj.addEventListener) obj.addEventListener(etype, fp, cap);
    else if (obj.attachEvent) obj.attachEvent("on" + etype, fp);
  }, 

  remove: function(obj, etype, fp, cap) {
    cap = cap || false;
    if (obj.removeEventListener) obj.removeEventListener(etype, fp, cap);
    else if (obj.detachEvent) obj.detachEvent("on" + etype, fp);
  }, 

  DOMit: function(e) { 
    e = e? e: window.event;
    e.tgt = e.srcElement? e.srcElement: e.target;
    
    if (!e.preventDefault) e.preventDefault = function () { return false; }
    if (!e.stopPropagation) e.stopPropagation = function () { if (window.event) window.event.cancelBubble = true; }
        
    return e;
  }
  
}














/*   dw_slidebar   version date: Feb 2004   requires dw_event.js   */

/*************************************************************************
  This code is from Dynamic Web Coding at http://www.dyn-web.com/
  Copyright 2004 by Sharon Paine 
  See Terms of Use at http://www.dyn-web.com/bus/terms.html
  regarding conditions under which you may use this code.
  This notice must be retained in the code as is!
*************************************************************************/

// model: Aaron Boodman's dom drag at www.youngpup.net
var dw_slidebar = {
  obj: null,
  slideDur: 500,  // duration of glide onclick of track  
  init: function (bar, track, axis, x, y) {
    x = x || 0; y = y || 0;
    bar.style.left = x + "px"; bar.style.top = y + "px";
    bar.axis = axis; track.bar = bar;
    if (axis == "h") {
      bar.trkWd = track.offsetWidth; // hold for setBarSize
      bar.maxX = bar.trkWd - bar.offsetWidth - x; 
      bar.minX = x; bar.maxY = y; bar.minY = y;
    } else {
      bar.trkHt = track.offsetHeight;
      bar.maxY = bar.trkHt - bar.offsetHeight - y; 
      bar.maxX = x; bar.minX = x; bar.minY = y;
    }
    bar.on_drag_start =  bar.on_drag =   bar.on_drag_end = 
    bar.on_slide_start = bar.on_slide =  bar.on_slide_end = function() {}
    bar.onmousedown = this.startDrag; track.onmousedown = this.startSlide;
  },
  
  startSlide: function(e) { // called onmousedown of track 
    if ( dw_slidebar.aniTimer ) clearInterval(dw_slidebar.aniTimer);
    e = e? e: window.event;
    var bar = dw_slidebar.obj = this.bar; // i.e., track's bar
    e.offX = (typeof e.layerX != "undefined")? e.layerX: e.offsetX;
    e.offY = (typeof e.layerY != "undefined")? e.layerY: e.offsetY;
    bar.startX = parseInt(bar.style.left); bar.startY = parseInt(bar.style.top);
    if (bar.axis == "v") {
      bar.destX = bar.startX;
      bar.destY = (e.offY < bar.startY)? e.offY: e.offY - bar.offsetHeight;
      bar.destY = Math.min( Math.max(bar.destY, bar.minY), bar.maxY );
    } else {
      bar.destX = (e.offX < bar.startX)? e.offX: e.offX - bar.offsetWidth;
      bar.destX = Math.min( Math.max(bar.destX, bar.minX), bar.maxX );
      bar.destY = bar.startY;
    }
    bar.distX = bar.destX - bar.startX; bar.distY = bar.destY - bar.startY;
    dw_slidebar.per = Math.PI/(2 * dw_slidebar.slideDur);
  	dw_slidebar.slideStart = (new Date()).getTime();
    bar.on_slide_start(bar.startX, bar.startY);
  	dw_slidebar.aniTimer = setInterval("dw_slidebar.doSlide()",10);
  },
  
  doSlide: function() {
    if ( !dw_slidebar.obj ) { clearInterval(dw_slidebar.aniTimer); return; }    
    var bar = dw_slidebar.obj;     
    var elapsed = (new Date()).getTime() - this.slideStart;
  	if (elapsed < this.slideDur) {
  		var x = bar.startX + bar.distX * Math.sin(this.per*elapsed);
  		var y = bar.startY + bar.distY * Math.sin(this.per*elapsed);
      bar.style.left = x + "px"; bar.style.top = y + "px";
      bar.on_slide(x, y);
  	} else {	// if time's up
      clearInterval(this.aniTimer);
      bar.style.left = bar.destX + "px"; bar.style.top = bar.destY + "px";
      bar.on_slide_end(bar.destX, bar.destY);
      this.obj = null;
  	}
  },
  
  startDrag: function (e) { // called onmousedown of bar 
    e = dw_event.DOMit(e);
    if ( dw_slidebar.aniTimer ) clearInterval(dw_slidebar.aniTimer);
    var bar = dw_slidebar.obj = this;
    bar.downX = e.clientX; bar.downY = e.clientY;
    bar.startX = parseInt(bar.style.left);
    bar.startY = parseInt(bar.style.top);
    bar.on_drag_start(bar.startX, bar.startY);
    dw_event.add( document, "mousemove", dw_slidebar.doDrag, true );
    dw_event.add( document, "mouseup",   dw_slidebar.endDrag,  true );
    e.stopPropagation();
  },

  doDrag: function (e) {
    e = e? e: window.event;
    if (!dw_slidebar.obj) return;
    var bar = dw_slidebar.obj; 
    var nx = bar.startX + e.clientX - bar.downX;
    var ny = bar.startY + e.clientY - bar.downY;
    nx = Math.min( Math.max( bar.minX, nx ), bar.maxX);
    ny = Math.min( Math.max( bar.minY, ny ), bar.maxY);
    bar.style.left = nx + "px"; bar.style.top  = ny + "px";
    bar.on_drag(nx,ny);
    return false;  
  },
  
  endDrag: function () {
    dw_event.remove( document, "mousemove", dw_slidebar.doDrag, true );
    dw_event.remove( document, "mouseup",   dw_slidebar.endDrag,  true );
    if ( !dw_slidebar.obj ) return; // avoid errors in ie if inappropriate selections
    dw_slidebar.obj.on_drag_end( parseInt(dw_slidebar.obj.style.left), parseInt(dw_slidebar.obj.style.top) );
    dw_slidebar.obj = null;  
  }
  
}





















/*
  dw_scroll_aux    version date: Feb 20, 2004  
  Adds scroll bar functionality to scrolling layers code
  (i.e., dw_scroll.js or dw_glidescroll.js, version date Feb 2004 or later)
  Also requires dw_slidebar.js, which requires dw_event.js
*/

/***************************************************************************
  This code is from Dynamic Web Coding at http://www.dyn-web.com/
  Copyright 2004 by Sharon Paine 
  See Terms of Use at http://www.dyn-web.com/bus/terms.html
  regarding conditions under which you may use this code.
  This notice must be retained in the code as is!
****************************************************************************/

// Size dragBar according to layer size?  
dw_scrollLayer.prototype.bSizeDragBar = true;

dw_scrollLayer.prototype.setUpScrollbar = function(id, trkId, axis, offx, offy) {
  if (!document.getElementById) return;
  var bar = document.getElementById(id);
  var trk = document.getElementById(trkId);
  dw_slidebar.init(bar, trk, axis, offx, offy);
  // connect dw_slidebar with dw_scrollLayer
  bar.wn = dw_scrollLayers[this.id]; // scroll area object this bar connected to
  if (axis == "v") this.vBarId = id; else this.hBarId = id;
  // also called on_load from loadLayer, but in case h and v scrollbars, need to call here too
  if (this.bSizeDragBar) this.setBarSize();
  bar.on_drag_start = bar.on_slide_start = dw_scrollLayer.getWndoLyrRef;
  bar.on_drag_end =   bar.on_slide_end =   dw_scrollLayer.tossWndoLyrRef;
  bar.on_drag =       bar.on_slide =       dw_scrollLayer.UpdateWndoLyrPos;
}

// for these 3 functions (assigned to bar.on_drag/slide...) "this" refers to bar
// get/discard ref to layer visible in scroll area
dw_scrollLayer.getWndoLyrRef = function()  { this.wnLyr = document.getElementById(this.wn.lyrId); }
dw_scrollLayer.tossWndoLyrRef = function() { this.wnLyr = null; }
// keep position of scrolling layer in synch with slide/drag of bar
dw_scrollLayer.UpdateWndoLyrPos = function(x, y) {
  var nx, ny;
  if (this.axis == "v") {
    nx = this.wn.x; // floating point values for loaded layer's position held in shiftTo method
    ny = -(y - this.minY) * ( this.wn.maxY / (this.maxY - this.minY) ) || 0;
  } else {
    ny = this.wn.y;
    nx = -(x - this.minX) * ( this.wn.maxX / (this.maxX - this.minX) ) || 0;
  }
  this.wn.shiftTo(this.wnLyr, nx, ny);
}

// Keep position of dragBar in sync with position of layer onscroll
dw_scrollLayer.prototype.updateScrollbar = function(x, y) {
  var nx, ny;
  if ( ( this.xdir == 0 || this.distX == 0 ) && this.vBarId ) {
    if (!this.maxY) return;
    ny = -( y * ( (this.bar.maxY - this.bar.minY) / this.maxY ) - this.bar.minY );
    ny = Math.min( Math.max(ny, this.bar.minY), this.bar.maxY);  
    nx = parseInt(this.bar.style.left);
  } else if ( ( this.ydir == 0 || this.distY == 0 ) && this.hBarId ) {
    if (!this.maxX) return;
    nx = -( x * ( (this.bar.maxX - this.bar.minX) / this.maxX ) - this.bar.minX );
    nx = Math.min( Math.max(nx, this.bar.minX), this.bar.maxX);
    ny = parseInt(this.bar.style.top);
  } 
  this.bar.style.left = nx + "px"; this.bar.style.top = ny + "px";
}

// Restore dragBar to start position when loading new layer
dw_scrollLayer.prototype.restoreScrollbars = function() {
  var bar;
  if (this.vBarId) {
    bar = document.getElementById(this.vBarId);
    bar.style.left = bar.minX + "px"; bar.style.top = bar.minY + "px";
  }
  if (this.hBarId) {
    bar = document.getElementById(this.hBarId);
    bar.style.left = bar.minX + "px"; bar.style.top = bar.minY + "px";
  }
}
  
// Size dragBar in proportion to size of content in layer
// called "on_load" of loadLayer method if bSizeDragBar prop true
dw_scrollLayer.prototype.setBarSize = function() {
  var lyr, wn, bar;
  lyr = document.getElementById(this.lyrId);
  wn = document.getElementById(this.id);
  if (this.vBarId) {
    bar = document.getElementById(this.vBarId);
    bar.style.height = (lyr.offsetHeight > wn.offsetHeight)? bar.trkHt / ( lyr.offsetHeight / wn.offsetHeight ) + "px": bar.trkHt - 2*bar.minY + "px";
    bar.maxY = bar.trkHt - bar.offsetHeight - bar.minY; 
  }
  if (this.hBarId) {
    bar = document.getElementById(this.hBarId);
    bar.style.width = (this.wd > wn.offsetWidth)? bar.trkWd / ( this.wd / wn.offsetWidth ) + "px": bar.trkWd - 2*bar.minX + "px";
    bar.maxX = bar.trkWd - bar.offsetWidth - bar.minX; 
  }
}

// called from loadLayer
dw_scrollLayer.prototype.on_load = function() { 
  this.restoreScrollbars();
  if (this.bSizeDragBar) this.setBarSize();
}

dw_scrollLayer.prototype.on_scroll = dw_scrollLayer.prototype.on_slide = function(x,y) { this.updateScrollbar(x,y); }

// obtain and discard references to relevant dragBar
dw_scrollLayer.prototype.on_scroll_start = dw_scrollLayer.prototype.on_slide_start = function() {
  if ( ( this.xdir == 0 || this.distX == 0 ) && this.vBarId ) this.bar = document.getElementById(this.vBarId);
  else if ( ( this.ydir == 0 || this.distY == 0 ) && this.hBarId ) this.bar = document.getElementById(this.hBarId);
}

dw_scrollLayer.prototype.on_scroll_end = dw_scrollLayer.prototype.on_slide_end = function(x, y) { 
  this.updateScrollbar(x,y);
  this.lyr = null; this.bar = null; 
}























var wndo = [];

// Necessary to avoid errors before page loaded
function dw_startScroll(num, dir, sp) {
  if ( wndo[num] && wndo[num].startScroll ) wndo[num].startScroll(dir, sp);
}

function dw_stopScroll(num) {
  if ( wndo[num] && wndo[num].stopScroll ) wndo[num].stopScroll();
}

function dw_loadLayer(num, id, cntId) {
  if ( wndo[num] && wndo[num].loadLayer ) wndo[num].loadLayer(id, cntId);
}

// increase speed onmousedown of scroll links
function dw_doubleSpeed(num) {
  if ( wndo[num] && wndo[num].speed ) wndo[num].speed *= 2;
}

function dw_resetSpeed(num) {
  if ( wndo[num] && wndo[num].speed ) wndo[num].speed /= 2;
}

function initScrollLayer() {
  // arguments: id of layer containing scrolling layers (clipped layer), id of layer to scroll,
  // if horizontal scrolling, id of element containing scrolling content (table?)
  wndo[0] = new dw_scrollLayer('wn', 'lyr1');

  // bSizeDragBar set true by default (explained at www.dyn-web.com/dhtml/scroll/ )
  // wndo.bSizeDragBar = false;

  // arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
  // (x/y offsets of dragBar in track)
  wndo[0].setUpScrollbar("dragBar", "track", "v", 1, 1);

  // pass id's of any wndo's that scroll inside tables
  // i.e., if you have 3 (with id's wn1, wn2, wn3): GeckoTableBugFix('wn1', 'wn2', 'wn3');
  GeckoTableBugFix('wn');
}
