function divScroller(id) {
	
	this.id = id;
	
	window["scroller"+id] = this;
}

divScroller.prototype.firstDiv = "first-pane";
divScroller.prototype.currentDiv = "first-pane"; // The default loaded section on the page
divScroller.prototype.divSuffix = "-pane";
divScroller.prototype.buttonSuffix = "-tab";
divScroller.prototype.parentDiv = "scroller";
divScroller.prototype.buttonDiv = "buttons";
divScroller.prototype.transDuration = 25; // milliseconds
divScroller.prototype.transType = "backOut";

divScroller.prototype.anchorTop = 0; // if set this will dynamically alter the padding-top and top style of the panes to manipulate the anchor position
divScroller.prototype.anchorPaddingTop = 0;

divScroller.prototype.scrollAnim = {time:0, begin:0, change:0.0, duration:0.0, element:null, timer:null};

divScroller.prototype.direction = "horiz"; /* EDIT CJ 11/9/2007 */
divScroller.prototype.setWrapperHeight = false; /* EDIT CJ 11/9/2007 - match wrapper height to height of its current div */

/*
	TYPES
	manual - div to div controlled by buttons clicks
	timed - div to div controlled by intervals
	continuous - continuous scroll
*/

divScroller.prototype.type = "manual";

divScroller.prototype.continuousSpeed = 50;
divScroller.prototype.continuousIncrement = 1;
divScroller.prototype.continuousLoopPoint = "middle-pane";

// only call this immediately after initiation

divScroller.prototype.init = function() {

	if (this.anchorTop != 0) {
		
		theScroll = document.getElementById(this.parentDiv);
		
		children = theScroll.getElementsByTagName("div");
		
		for (i = 0; i < children.length; i++) {
			if (children[i].id.indexOf(this.divSuffix) > 0) {
				children[i].style.paddingTop = this.anchorPaddingTop + "px";
				children[i].style.top = this.anchorTop + "px";
			}
		}
		
		//alert(children.length);
	}

	if (window.location.hash.length) {
	
		hashDiv = window.location.hash.substring(1);
		
		if (this.currentDiv == hashDiv) {
			return;
		}
		
		sectionTab = hashDiv.split("-")[0] + this.buttonSuffix;
    
		if (document.getElementById(sectionTab)) {
		
			document.getElementById(sectionTab).className = "active";
			lastTab = this.currentDiv.split("-")[0] + this.buttonSuffix;
			tab = document.getElementById(lastTab)
			if (tab) {
				tab.className = "inactive";
			}
		
			this.currentDiv = hashDiv;
		}
		
	}
	
	// check for dud pane
	if (this.firstDiv !== this.currentDiv && this.currentDiv !== "") {
		
		theScroll = document.getElementById(this.parentDiv);
		position = this.findElementPos(document.getElementById(this.currentDiv));
		offsetPos = this.findElementPos(document.getElementById(this.firstDiv));
		
		// alert('position[0]=' + position[0] + 'position[1]=' + position[1]);
		
		position[0] = position[0] - offsetPos[0];
		
		theScroll.scrollLeft = position[0];
		
		if (this.setWrapperHeight == true) {
			// alert(document.getElementById(this.currentDiv).offsetHeight); // alert(theScroll.style.height);
			theScroll.style.height = document.getElementById(this.currentDiv).offsetHeight + 'px';
			// alert(theScroll.style.height); // alert('position[0]=' + position[0] + 'position[1]=' + position[1]);
		}
		
		/*current = this.currentDiv;
		this.currentDiv = this.firstDiv;
		
		this.ScrollDiv(current);*/
	}
	
	if (this.type == "continuous") { // need to double up content so it will scroll through and loop back cleanly
	
		this.scrollAnim.element = document.getElementById(this.parentDiv);
		offset = this.findElementPos(document.getElementById(this.firstDiv));
		midpoint = this.findElementPos(document.getElementById(this.continuousLoopPoint));
		this.scrollAnim.begin = midpoint[0] - offset[0]; // hack in for simplicity
		this.scrollAnim.timer = window.setInterval("window.scroller"+this.id+".ContinuousScrollDiv()", this.continuousSpeed);
	}
}

// Continuous scroll

divScroller.prototype.ContinuousScrollDiv = function() {
	
	if (this.scrollAnim.begin == this.scrollAnim.element.scrollLeft) {
		this.scrollAnim.element.scrollLeft = 0;
	}
	
	this.scrollAnim.element.scrollLeft += this.continuousIncrement;
}

// Scroll the page manually to the position of element "scrollDiv", passed to us.

divScroller.prototype.ScrollDiv = function(scrollDiv) {

	// Store the last section, and update the current section

	if (this.currentDiv == scrollDiv) {
		return;
	}
	lastSection = this.currentDiv;
	this.currentDiv = scrollDiv;
	
	// Change the section highlight.
	// Extract the root section name, and use that to change the background image to 'top', revealing the alt. state

    sectionTab = this.currentDiv.split("-")[0] + this.buttonSuffix;
    
    if (document.getElementById(sectionTab)) { /* EDIT CJ 11/9/2007 */
	
		document.getElementById(sectionTab).className = "active";
		if (lastSection) {
			lastTab = lastSection.split("-")[0] + this.buttonSuffix;
			tab = document.getElementById(lastTab)
			if (tab) {
				tab.className = "inactive";
			}
		}
	
	} /* EDIT CJ 11/9/2007 */
    
	// Get the element we want to scroll, get the position of the element to scroll to
	
	theScroll = document.getElementById(this.parentDiv);
	// alert(document.getElementById(scrollDiv));
	
	if (document.getElementById(scrollDiv)) { /* EDIT CJ 11/9/2007 */
		position = this.findElementPos(document.getElementById(scrollDiv));
	} /* EDIT */
	else { /* EDIT */
		return; /* EDIT */
	} /* EDIT */
	
	// Get the position of the offset div -- the first div / at the far left.
	// This is the amount we compensate for when scrolling
	
	if (this.firstDiv != "") {
		offsetPos = this.findElementPos(document.getElementById(this.firstDiv));
		position[0] = position[0] - offsetPos[0];
		position[1] = position[1] - offsetPos[1]; /* EDIT CJ 11/9/2007 */
	}

	if (this.direction == 'horiz') {
		this.scrollStart(theScroll, theScroll.scrollLeft, position[0], "horiz");
	}
	else {
		// alert('this.scrollStart(' + this.parentDiv + ', ' + theScroll.scrollTop + ' , ' + position[1] + ', "vert");');
		this.scrollStart(theScroll, theScroll.scrollTop, position[1], "vert");
	}
	
	return true; /* EDIT CJ 11/9/2007 - need to know if we have successfully moved inside 
					numbered divs so we can calculate the next/prev divs again - have 
					added return false if scrollDiv does not exist inside this method */
	
	// return false;
}

// Scroll the page using the arrows

divScroller.prototype.ScrollArrow = function(direction) {

	toolbarElem = document.getElementById(this.buttonDiv);
	toolbarNames = new Array();
    
	// Find all the <li> elements in the toolbar, and extract their id's into an array.
    
	if (toolbarElem.hasChildNodes()) {
	
		var children = toolbarElem.childNodes;
		for (var i = 0; i < children.length; i++) {
			if (toolbarElem.childNodes[i].tagName == "LI" || toolbarElem.childNodes[i].tagName == "li") {
				toolbarNames.push(toolbarElem.childNodes[i].id.split("-")[0]);
			}
		}
	}

	// Now iterate through our array of tab names, find matches, and determine where to go.
	
	for (var i = 0; i < toolbarNames.length; i++) {
		if (toolbarNames[i] == this.currentDiv.split("-")[0]) {
			if (direction == "left") {
				if (i - 1 < 0) {
					gotoTab = toolbarNames[toolbarNames.length - 1];
				} else {
					gotoTab = toolbarNames[i - 1];
				}
			} else {
				if ((i + 1) > (toolbarNames.length - 1)) {
					gotoTab = toolbarNames[0];
				} else {
					gotoTab = toolbarNames[i + 1];
				}
			}
		}
	}
	
	// Go to the section name!
	
	this.ScrollDiv(gotoTab+this.divSuffix);

}

//
// Animated Scroll Functions
//



divScroller.prototype.scrollStart = function(elem, start, end, direction) {

	// console.log("scrollStart from "+start+" to "+end+" in direction "+direction);

	if (this.scrollAnim.timer != null) {
		window.clearInterval(this.scrollAnim.timer);
		this.scrollAnim.timer = null;
	}
	this.scrollAnim.time = 0;
	this.scrollAnim.begin = start;
	this.scrollAnim.change = end - start;
	this.scrollAnim.duration = this.transDuration;
	this.scrollAnim.element = elem;
	
	if (this.setWrapperHeight == true) {
		document.getElementById(this.parentDiv).style.height = document.getElementById(this.currentDiv).offsetHeight + 'px';
	}

	if (direction == "horiz") {
		this.scrollAnim.timer = window.setInterval("window.scroller"+this.id+".scrollHorizAnim()", 15);
	}
	else {
		
		this.scrollAnim.timer = window.setInterval("window.scroller"+this.id+".scrollVertAnim()", 15);
	}
}

divScroller.prototype.scrollVertAnim = function() {
		
	if (this.scrollAnim.time > this.scrollAnim.duration) {
		window.clearInterval(this.scrollAnim.timer);
		this.scrollAnim.timer = null;
		document.getElementById(this.parentDiv).style.height = document.getElementById(this.currentDiv).offsetHeight + 'px';
	}
	else {
		move = this.callAnimation(this.transType, this.scrollAnim.time, this.scrollAnim.begin, this.scrollAnim.change, this.scrollAnim.duration);
		this.scrollAnim.element.scrollTop = move; 
		this.scrollAnim.time++;
	}
}

divScroller.prototype.scrollHorizAnim = function() {

	if (this.scrollAnim.time > this.scrollAnim.duration) {
		window.clearInterval(this.scrollAnim.timer);
		this.scrollAnim.timer = null;
	}
	else {
		move = this.callAnimation(this.transType,this.scrollAnim.time, this.scrollAnim.begin, this.scrollAnim.change, this.scrollAnim.duration);
		this.scrollAnim.element.scrollLeft = move;
		this.scrollAnim.time++;
	}
}

divScroller.prototype.findElementPos = function(elemFind) {
	var elemX = 0;
	var elemY = 0;
	do {
		elemX += elemFind.offsetLeft;
		elemY += elemFind.offsetTop;
	} while ( elemFind = elemFind.offsetParent )

	//console.log("Found element "+elemFind+" at "+elemY+"/"+elemX);

	return Array(elemX, elemY);
}


divScroller.prototype.callAnimation = function(func, t, b, c, d) {
	
	switch(func) {
		
		case "sineInOut":
		return this.sineInOut(t, b, c, d);
		
		case "quadInOut":
		return this.quadInOut(t, b, c, d);
		
		case "cubicOut":
		return this.cubicOut(t, b, c, d);
		
		case "cubicInOut":
		return this.cubicInOut(t, b, c, d);
		
		case "quartOut":
		return this.quartOut(t, b, c, d);
		
		case "quartInOut":
		return this.quartInOut(t, b, c, d);
		
		case "quintOut":
		return this.quintOut(t, b, c, d);
		
		case "quintInOut":
		return this.quintInOut(t, b, c, d);
		
		case "expoInOut":
		return this.expoInOut(t, b, c, d);
		
		case "expoOut":
		return this.expoOut(t, b, c, d);
		
		case "circOut":
		return this.circOut(t, b, c, d);
		
		case "circInOut":
		return this.circInOut(t, b, c, d);
		
		case "backIn":
		return this.backIn(t, b, c, d);
		
		case "backOut":
		return this.backOut(t, b, c, d);
		
		case "backInOut":
		return this.backInOut(t, b, c, d);
		
		case "bounceIn":
		return this.bounceIn(t, b, c, d);
		
		case "bounceInOut":
		return this.bounceInOut(t, b, c, d);
		
		case "bounceOut":
		return this.bounceOut(t, b, c, d);
		
	}
}


/*

	http://snippets.dzone.com/user/sikelianos/tag/penner
	
*/

divScroller.prototype.sineInOut = function(t, b, c, d) {
	return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
}

divScroller.prototype.quadInOut = function (t, b, c, d) {
	t /= d/2;
	if (t < 1) return c/2*t*t + b;
	t--;
	return -c/2 * (t*(t-2) - 1) + b;
}

divScroller.prototype.cubicOut = function (t, b, c, d) {
	t /= d;
	t--;
	return c*(t*t*t + 1) + b;
}

divScroller.prototype.cubicInOut = function (t, b, c, d) {
	t /= d/2;
	if (t < 1) return c/2*t*t*t + b;
	t -= 2;
	return c/2*(t*t*t + 2) + b;
}

divScroller.prototype.quartOut = function (t, b, c, d) {
	return -c * ((t=t/d-1)*t*t*t - 1) + b;
}

divScroller.prototype.quartInOut = function (t, b, c, d) {
	t /= d/2;
	if (t < 1) return c/2*t*t*t*t + b;
	t -= 2;
	return -c/2 * (t*t*t*t - 2) + b;
}

divScroller.prototype.quintOut = function (t, b, c, d) {
	return c*((t=t/d-1)*t*t*t*t + 1) + b;
}

divScroller.prototype.quintInOut = function (t, b, c, d) {
	t /= d/2;
	if (t < 1) return c/2*t*t*t*t*t + b;
	t -= 2;
	return c/2*(t*t*t*t*t + 2) + b;
}

divScroller.prototype.expoInOut = function (t, b, c, d) {
	var flip = 1;
	if (c < 0) {
		flip *= -1;
		c *= -1;
	}
	if (t < d/2) return flip * (Math.exp(2*Math.log(c/2)/d * t)) + b;
	return flip * (-Math.exp(-2*Math.log(c/2)/d * (t-d)) + c + 1) + b;
}

divScroller.prototype.expoOut = function (t, b, c, d) {
	var flip = 1;
	if (c < 0) {
		flip *= -1;
		c *= -1;
	}
	return flip * (-Math.exp(-Math.log(c)/d * (t-d)) + c + 1) + b;
}
		
divScroller.prototype.circOut = function (t, b, c, d) {
	return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
}

divScroller.prototype.circInOut = function (t, b, c, d) {
	t /= d/2;
	if (t < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
	t -= 2;
	return c/2 * (Math.sqrt(1 - t*t) + 1) + b;
}

/* Need Dud Div at start to use these cleanly */

divScroller.prototype.backIn = function (t, b, c, d, s) {
	if (s == undefined) s = 1.70158;
	return c*(t/=d)*t*((s+1)*t - s) + b;
}

divScroller.prototype.backOut = function (t, b, c, d, s) {
	if (s == undefined) s = 1.70158;
	return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
}

divScroller.prototype.backInOut = function (t, b, c, d, s) {
	if (s == undefined) s = 1.70158; 
	if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
	return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
}

divScroller.prototype.bounceIn = function (t, b, c, d) {
	return c - this.bounceOut (d-t, 0, c, d) + b;
}

divScroller.prototype.bounceOut = function (t, b, c, d) {
	if ((t/=d) < (1/2.75)) {
		return c*(7.5625*t*t) + b;
	} else if (t < (2/2.75)) {
		return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
	} else if (t < (2.5/2.75)) {
		return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
	} else {
		return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
	}
}

divScroller.prototype.bounceInOut = function (t, b, c, d) {
	if (t < d/2) return this.bounceIn (t*2, 0, c, d) * .5 + b;
	return this.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b;
}
