//=========================================================
// custom scroller developed for 2027.org by aaron boodman
//
// some sections based on ypSimpleScroll.js.
//
// www.youngpup.net
// 3/28/2001 (3 hours before site launch!)
//
// updated
// - 8/29/02 : fixed performance issues related to using
//   background images
//=========================================================
// code is art!
//=========================================================

var gsScroll = null;

function Scroller(asName)
{
	this.name        = asName;
	this.speed       = 100;
	this.aniLen      = 1000;
	this.clipH       = 0;
	this.thumbMax    = -1;
	this.thumbH      = 100;
	this.scrollbarH  = 0;
	this.scrollTop   = 0;
	this.scrollLeft  = 0;
	this.minRes      = 0;
	this.ie4         = navigator.appName == "Microsoft Internet Explorer" && !document.getElementById;
	this.ns4         = document.layers ? 1 : 0;
	this.dom         = document.getElementById ? 1 : 0;
	this.mac         = navigator.platform == "MacPPC";
	this.mo5         = navigator.userAgent.indexOf("Gecko") != -1;
	this.dir         = 0;
	this.lastTime    = 0;
	this.aniTimer    = 0;
	this.dragActive  = 0;
	this.dragLastY   = 0;
	this.dragStartOffset = 0;
	this.startPos    = 0;
	this.startTime   = 0;
	this.accel       = 0;
	this.endPos      = 0;
	this.dist        = 0;
	this.lyrFrame, this.lyrScrollbar, this.lyrScrollbarGlobal, this.lyrThumb, this.lyrMarker, this.lyrElevUp, this.lyrElevDn, this.lyrContainer, this.lyrContent;
	
	this.init = function()
	{
		// gather pieces
		this.lyrFrame           = this.getLyr("scroller"+this.name, document)
		this.lyrScrollbar       = this.getLyr("scrollbar"+this.name, this.lyrFrame)
		this.lyrScrollbarGlobal = this.getLyr("scrollbarGlobal"+this.name, this.lyrFrame)
		this.lyrThumb           = this.getLyr("thumb"+this.name, this.lyrScrollbar)
		this.lyrMarker          = this.getLyr("marker"+this.name, this.lyrScrollbar)
		this.lyrElevUp          = this.getLyr("elevUp"+this.name, this.lyrScrollbar)
		this.lyrElevDn          = this.getLyr("elevDn"+this.name, this.lyrScrollbar)
		this.lyrContainer       = this.getLyr("container"+this.name, this.lyrFrame)
		this.lyrContent         = this.getLyr("content"+this.name, this.lyrContainer)
		
		this.clipH = this.lyrFrame.offsetHeight;
		this.scrollbarH = this.lyrScrollbarGlobal.clientHeight-19;
		this.thumbMax = this.lyrScrollbarGlobal.clientHeight-19-this.thumbH;
		
		// calculate some values
		this.docH            = Math.max(this.ns4 ? this.lyrContent.document.height : this.lyrContent.offsetHeight, this.clipH)
		this.scrollH         = this.docH - this.scrollbarH - 19;
		
		if (this.docH > this.clipH)
		{
			// hook events
			this.lyrElevUp.onmousedown   = this.slideTo
			this.lyrElevDn.onmousedown   = this.slideTo
			this.lyrThumb.onmousedown    = this.startDrag
			this.lyrThumb.ondragstart    = function() { return false; }
			this.lyrElevUp.onmouseover   = function() { this.sObj.toggleElev(this.sObj.lyrElevUp, 2) }
			this.lyrElevUp.onmouseout    = function() { this.sObj.toggleElev(this.sObj.lyrElevUp, 1) }
			this.lyrElevDn.onmouseover   = function() { this.sObj.toggleElev(this.sObj.lyrElevDn, 2) }
			this.lyrElevDn.onmouseout    = function() { this.sObj.toggleElev(this.sObj.lyrElevDn, 1) }
			
			// initialize some settings
			this.lyrThumb.s.top = "-1px";
			
			// ns4 bullshit.
			if (document.layers)
			{
				this.lyrThumb.captureEvents(Event.MOUSEDOWN)
				this.lyrElevDn.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE)
				this.lyrElevUp.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE)
			}
			
			// mozilla5 bullshit.
			if (this.mo5) document.getElementById("scrollerMo5Shim").style.height = this.docH
			this.jumpTo(-1);
		}
		else
		{
			this.lyrScrollbarGlobal.s.visibility = 'hidden';
		}
		
		// all done!
		this.loaded = true
	}
	
	this.startScroll = function(dir) {
		if (this.aniTimer) window.clearTimeout(this.aniTimer)
		this.dir		   = dir
		this.lastTime	= (new Date()).getTime() - this.minRes
		this.startPos	= this.scrollTop
		this.aniTimer	= window.setTimeout("Scroller.scroll()", this.minRes)
	}
	
	this.scroll = function() {
		this.aniTimer	= window.setTimeout("Scroller.scroll()", this.minRes)
		var now			= (new Date()).getTime()
		var elapsed		= now - this.lastTime
		var ny			= eval(this.scrollTop + this.dir + (elapsed * this.speed / 1000))
		this.lastTime	= now
		if (ny > this.scrollH && this.dir == "+" || ny < 0 && this.dir == "-") {
			this.endScroll()
			this.jumpTo(this.dir == "+" ? this.scrollH : 0)
		}
		else this.jumpTo(ny)
	}
	
	this.endScroll = function() {
		if (this.aniTimer) this.aniTimer = window.clearTimeout(this.aniTimer)
	}
	
	this.startDrag = function(e) {
		if (!e) e = window.event
		if (this.sObj.aniTimer) window.clearTimeout(this.sObj.aniTimer)
		var ey = e.clientY ? e.clientY : e.y
		this.sObj.dragLastY = ey
		this.sObj.dragStartOffset = ey - parseInt(this.sObj.lyrThumb.s.top)
		this.sObj.dragActive = true
		if (this.sObj.ns4) window.document.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP)
		gsScroll = this.sObj;
		window.document.onmousemove = gsScroll.doDrag
		window.document.onmouseup = gsScroll.stopDrag
		//this.sObj.lyrFrame.onmousemove = this.sObj.doDrag;
		//this.sObj.lyrFrame.onmouseup = this.sObj.stopDrag;
		return false
	}
	
	this.doDrag = function(e) {
		if (!e) e = window.event
		var ey = (e.clientY ? e.clientY : e.y)
		var dy = ey - gsScroll.dragLastY
		var ny = parseInt(gsScroll.lyrThumb.s.top) + dy
		// constrain
		if (ny >= gsScroll.thumbMax) gsScroll.dragLastY = gsScroll.thumbMax + gsScroll.dragStartOffset
		else if (ny < 0) gsScroll.dragLastY = gsScroll.dragStartOffset
		else gsScroll.dragLastY = ey
		ny = Math.min(Math.max(ny, 0), gsScroll.thumbMax)
		gsScroll.jumpTo(ny * gsScroll.scrollH / gsScroll.thumbMax)
		return false;
	}
	
	this.stopDrag = function() {
		//gsScroll = this.sObj;
		gsScroll.dragActive = false
		if (gsScroll.ns4) window.document.releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP)
		window.document.onmousemove = null
		window.document.onmouseup   = null
		//this.sObj.lyrFrame.onmousemove = null;
		//this.sObj.lyrFrame.onmouseup = null;
	}
	
	// slideTo gets called in the scope of lyrElevUp or lyrElevDn
	this.slideTo = function(e) {
		if (!e) e = window.event
		var ey = e.offsetY ? e.offsetY : e.layerY
		if (typeof ey == "undefined") ey = 0
		var ny = (this.id == "elevDn") ? ey-5 : ey
		ny += this.s.top == "" ? 0 : parseInt(this.s.top)
		ny *= this.sObj.scrollH / this.sObj.thumbMax
		ny = Math.min(ny, this.sObj.scrollH)
		this.sObj.startTime = (new Date()).getTime()
		this.sObj.startPos = this.sObj.scrollTop
		this.sObj.endPos = ny;
		this.sObj.dist = this.sObj.endPos - this.sObj.startPos
		this.sObj.accel = this.sObj.dist / 1000 / 1000
		if (this.sObj.aniTimer) this.sObj.aniTimer = window.clearInterval(aniTimer)
		gsScroll = this.sObj;
		this.sObj.aniTimer = window.setInterval("gsScroll.slide()", 10)
	}
	
	this.slide = function() {
		var now = (new Date()).getTime()
		var elapsed = now - this.startTime
		if (elapsed > 1000) this.endScroll()
		else {
			var t = 1000 - elapsed
			var ny = this.endPos - t * t * this.accel
			this.jumpTo(ny)
		}
	}
	
	this.jumpTo = function(ny) {
		var thumbTop = Math.round(ny * this.thumbMax / this.scrollH);
		this.lyrElevUp[document.layers ? "clip" : "style"].height = thumbTop + 'px';
		this.lyrElevDn[document.layers ? "clip" : "style"].height = this.scrollbarH - thumbTop + 'px';
		this.lyrElevDn.s.top = thumbTop -1 + 'px';
		this.lyrThumb.s.top = thumbTop + 'px';
		this.lyrContent.s.top = -ny + 'px';
		this.scrollTop = ny;
	}
	
	this.toggleElev = function(lyr, iState) {
		var img = this["imgElevBack" + iState];
		if (document.layers) lyr.document.images[0].src = img.src;
		//else lyr.firstChild.src = img.src;
		lyr.onmousemove = iState == 2 ? this.moveMarker : null
		if (iState == 1) this.lyrMarker.s.visibility = "hidden"
	}
	
	this.moveMarker = function(e) {
		if (!this.sObj.lyrThumb.active) {
			if (!e) e = window.event
			var ey = e.layerY ? e.layerY : e.offsetY
			if (isNaN(ey)) ey = 0
			var ny = Math.round(ey / 2) * 2
			ny += (this.s.top == "" ? 0 : parseInt(this.s.top))
			ny -= 1
			this.sObj.lyrMarker.s.top = ny
			this.sObj.lyrMarker.s.visibility = "visible"
		}
	}
	
	this.toggleButton = function(suffix, iState) {
		var lyr = eval("Scroller.lyrScroll" + suffix)
		var img = this.getFirstImage(lyr)
		img.src = "scroll"+suffix+iState+".gif"
	}
	
	this.getLyr = function(sLyrId, oNestRef) {
		var o
		if (document.all) o = oNestRef.all[sLyrId]
		else if (document.layers) o = oNestRef.layers[sLyrId]
		else o = this.recursiveNs6Get(sLyrId, oNestRef)
		o.s = document.layers ? o : o.style
		o.sObj = this;
		return o
	}
	
	// this is kinda slow for ns6 ->
	// but best way I could think of w/o totally bloating the code.
	this.recursiveNs6Get = function(id, p) {
		if (p.childNodes) {
			for (var i = 0; i < p.childNodes.length; i++) {
				if (p.childNodes[i].id == id) return p.childNodes[i]
				else if (p.childNodes[i].childNodes.length > 0) {
					var obj = this.recursiveNs6Get(id, p.childNodes[i])
					if (obj && obj != null) return obj
				}
			}
		}
		return false
	}
	
	this.getFirstImage = function(lyr) {
		return document.layers ? lyr.document.images[0] : document.all ? lyr.all.tags("IMG")[0] : lyr.getElementsByTagName("IMG")[0]
	}
}

function ypImage(s) {
	var oImg  = new Image()
	oImg.src = s
	return oImg
}

function dbg(obj) {
	var s = ""
	for (prop in obj) s += prop + ":" + obj[prop] + "\n"
	alert(s)
}
