/*

Scroller (the unobtrusive mix, feat. Jay Skript And The Domsters)
by dotjay, 2006

Usage:
Automatically attaches onClick event handlers to internal links. Just include the script!
Assumes id attribute is used for destinations and not the name attribute. Can be easily reworked.
Assumes presence of the useful addLoadEvent() function (included at the top of the script)
 written by Simon Willison:
http://simon.incutio.com/archive/2004/05/26/addLoadEvent

Enjoy!

Known issues:
1) When using this script, the back button will no longer refocus to the target element on the page.
2) Safari doesn't like the location object very much, getting stuck with loading the page (see scrollTo function).
 Nothing I've tried fixes it.
 http://www.quirksmode.org/bugreports/archives/2005/05/Safari_13_visual_anomaly_with_windowlocationhref.html
 http://www.quirksmode.org/bugreports/archives/2005/06/Setting_locationhash_to_the_same_value_twice_cause.html
3) The scroller will thump into the bottom of the page when destinations cannot be brought to the top of the viewport.
 May be able to detect whether or not the bottom of the page will be hit.

--

Code based on ScrollWin by Travis Beckham, squidfingers.com

Originally borrowed from the Agape website, agape.org.uk

Rehashed to be unobtrusive with help from the following lovely people:
Stuart Langridge, kryogenix.org
James Edwards, brothercake.com
Cameron Adams, themaninblue.com
Peter-Paul Koch, quirksmode.org
Jon Tan, gr0w.com

References:
http://kryogenix.org/code/browser/smoothscroll/
http://www.doxdesk.com/personal/posts/evolt/20020422-pos.html
http://www.quirksmode.org/viewport/compatibility.html
http://www.sitepoint.com/books/jsant1/

*/



/* --- Required helper functions ---
*/

// generic onload event function by Simon Willison, http://simonwillison.net/2004/May/26/addLoadEvent/
/*function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') window.onload = func;
	else {
		window.onload = function() {
			if (oldonload) oldonload();
			func();
		}
	}
}*/

function attachEventListener(target,eventType,functionRef,capture) {
	if (typeof target.addEventListener != "undefined") target.addEventListener(eventType, functionRef, capture);
	else if (typeof target.attachEvent != "undefined") target.attachEvent("on" + eventType, functionRef);
	else {
		eventType = "on" + eventType;

		if (typeof target[eventType] == "function") {
			var oldListener = target[eventType];

			target[eventType] = function() {
				oldListener();
				return functionRef();
			};
		}
		else target[eventType] = functionRef;
	}
}


// can probably come up with something better than this...
function stopDefaultEvent(e) {
	e.returnValue = false;
	if (typeof e.preventDefault != "undefined") e.preventDefault();
}

// this would probably be better
/*
function stopDefaultEvent(e) {
	if (window.event) {
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	}
	if (e && e.preventDefault && e.stopPropagation) {
		e.preventDefault();
		e.stopPropagation();
	}
}
*/



/* --- Scroller ---
*/

var Scroller = {
	// properties
	isLooping: false,
	sourceElement: null,
	destinationElement: null,
	lastPosition: null,
	scrollInterval: null,

	// methods
	getCurrentOffset : function(){
		var x = 0,y = 0;
		// all except IE
		if(self.pageYOffset){
			x = self.pageXOffset;
			y = self.pageYOffset;
		}
		// IE 6 Strict Mode
		else if(document.documentElement && document.documentElement.scrollTop){
			x = document.documentElement.scrollLeft;
			y = document.documentElement.scrollTop;
		}
		// other IE
		else if(document.body && document.body.scrollTop){
			x = document.body.scrollLeft;
			y = document.body.scrollTop;
		}
		return [x,y];
	},

	getElementPosition : function(el){
		var x = 0,y = 0;
		if(el.offsetParent){
			while(el != null){
				x += el.offsetLeft;
				y += el.offsetTop;
				el = el.offsetParent;
			}
		}
		else if (el.x) {
			x += el.x;
			y += el.y;
		}
 		return [x,y];
	},

	scroll : function(source){
		if(this.isLooping){
			clearInterval(this.scrollInterval);
			this.isLooping = false;
			this.scrollInterval = null;
		}

		var container = document.body;
		this.sourceElement = source;
		this.destinationElement = document.getElementById(source.hash.substr(1));

		// where do we want to go?
		var position = this.getElementPosition(this.destinationElement);

		// start scroll loop (only scroll y)
		this.scrollTo(0, position[1]);
	},

	scrollTo : function(x,y){
		if(this.isLooping){
			var currentOffset = this.getCurrentOffset();
			var currentX = currentOffset[0], currentY = currentOffset[1];

			// have we arrived at the destination, or perhaps hit the edge of the page?
			if( (Math.abs(currentX-x) <= 1 && Math.abs(currentY-y) <= 1) || (this.lastPosition != null && currentY == this.lastPosition[1])){
				clearInterval(this.scrollInterval);
				this.isLooping = false;
				this.scrollInterval = null;
				this.lastPosition = null;

				// scroll is complete, so set location
				location.hash = this.sourceElement.hash.substr(1);
			}else{
				this.lastPosition = [currentX,currentY];
			 	window.scrollTo(currentX +(x-currentX)/2,currentY+(y-currentY)/2);
	 		}
		}else{
			this.scrollInterval = setInterval("Scroller.scrollTo("+x+","+y+")",100);
			this.isLooping = true;
		}
	}
};

function initInternalLinkScroller() {
	// while we only need getElementsByTagName here, there's no point continuing 
	// if we cannot locate the destination element later using getElementById
	if(!(document.getElementById && document.getElementsByTagName)) return;

	var allAnchors = document.getElementsByTagName("a");

	var numLinks = allAnchors.length;

	for (var i=0;i<numLinks;i++) {
 		var a = allAnchors[i];
		if ((a.href && a.href.indexOf('#') != -1)
			&& ( (a.pathname == location.pathname) || ('/'+a.pathname == location.pathname) )
			&& (a.search == location.search)) {

			a.onclick = function(e) {


				// prevent default
				if (typeof e == "undefined") e = window.event;
				stopDefaultEvent(e);
				// if you find the above doesn't work, try this instead:
				/*
				if (window.event) {
					window.event.cancelBubble = true;
					window.event.returnValue = false;
				}
				if (e && e.preventDefault && e.stopPropagation) {
					e.preventDefault();
					e.stopPropagation();
				}
				*/

				// do scroll
				Scroller.scroll(this);
			}
			if (a.captureEvents) a.captureEvents(Event.CLICK);

		}
	}
}

addLoadEvent(initInternalLinkScroller);

