Event.observe(window, 'load', function(){ window.ws = new WindowScroller();});

function WindowScroller (windowRef) {
	if (!windowRef) {
		this.windowRef = window;
	} else {
		this.windowRef = windowRef;
	}
	
	/* the frequence in which is moved */
	this.dt = 25;
	
	this.targetX;
	this.targetY;
	
	this.curX;
	this.curY;
	
	this.startX;
	this.startY;
	
	this.errors = new Array(); // holds Error objects
}

WindowScroller.prototype.scrollSmothlyBy = function (dx, dy) {

	this.prepareScrolling();

	this.targetX =  this.curX + dx;
	this.targetY =  this.curY + dy;

	this.prepareScrolling(); // has to run again now after setting the target to set  the direction
	this.doScrolling ();
}


WindowScroller.prototype.scrollToElement = function (elementId, bleedingX_arg, bleedingY_arg) {
	
	var bleedingX = bleedingX_arg || 10;
	var bleedingY = bleedingY_arg || 10;

	var el = $(elementId);
	var ElementPosArray = this._findPos(el);

	this.targetX = ElementPosArray[0] - bleedingX;
	this.targetY = ElementPosArray[1] - bleedingY;
	//if (debugConsole) debugConsole.show('targetPos', this.targetX + ', ' + this.targetY);
	this.prepareScrolling();
	this.doScrolling();
}

/* prepares things like setting the start and direction vars */

WindowScroller.prototype.prepareScrolling = function () {

	// start position
	this._determineCurrentScrollPosition ();
	this.startX = this.curX;
	this.startY = this.curY;
	
	// direction indicators
	this.directionIndicatorX = +1;
	this.directionIndicatorY = +1;
	if (this.startX > this.targetX) this.directionIndicatorX = -1 ;
	if (this.startY > this.targetY) this.directionIndicatorY = -1 ;
	
	// debug:
	//if (debugConsole)  debugConsole.show('status', 'running');
}


/*
 * this function will be used recursively:
 */

WindowScroller.prototype._findPos = function (obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}



WindowScroller.prototype.doScrolling = function() {
	
	// get references to the windowscroll and window objects:
	var w = this.windowRef; 
	var ws = this.windowRef.ws;
	ws._determineCurrentScrollPosition();

	var curX = ws.curX ;
	var curY = ws.curY ;

	var tarX = ws.targetX;
	var tarY = ws.targetY;
		
	var stepX = ws._calculateStepDistance(ws.startX, ws.curX, ws.targetX);
	var stepY = ws._calculateStepDistance(ws.startY, ws.curY, ws.targetY);
	
	// various break or continue conditions:

	// 1. the target has been reached:
	// these distance vars become negative if the target has been reached and passed.
	var distanceX = (tarX - curX) * ws.directionIndicatorX;
	var distanceY = (tarY - curY) * ws.directionIndicatorY; 
	//if (debugConsole) debugConsole.show('distanceX', distanceX);
	//if (debugConsole) debugConsole.show('distanceY', distanceY);
	var targetIsReached = distanceX < 1 && distanceY < 1;
	if (distanceX < 1) stepX = 0; // this _is_ necessary to break movement into one direction!
	if (distanceY < 1) stepY = 0;
	
	// 2. the target is unreachable, and we are still moving:
	var targetXIsUnreachable = false;
	var targetYIsUnreachable = false;
	if (ws.lastCurX == curX) {targetXIsUnreachable = true;} 
	//if (debugConsole) debugConsole.show('targetXIsUnreachable',targetXIsUnreachable); 
	if (ws.lastCurY == curY) {targetYIsUnreachable = true;} 
	//if (debugConsole) debugConsole.show('targetYIsUnreachable',targetYIsUnreachable); 
	var targetIsUnreachable = targetXIsUnreachable && targetYIsUnreachable;
	// If one direction is unreachable and the other has been reached
	// there is no need to expicitly check for this, because in that case 
	// lastCurZ and curZ will be the same as well.  
	ws.lastCurX = curX;
	ws.lastCurY = curY;
	
	// 3. some error is listed in ws.errors :
	var someErrorOcurred = false;
	if (ws.errors.length != 0) {someErrorOcurred = true};
	//if (debugConsole) debugConsole.show ('stepX', stepX);
	//if (debugConsole) debugConsole.show ('stepY', stepY);
	

	if (! targetIsReached 
		&& ! targetIsUnreachable
		&& ! someErrorOcurred 
		
		) 
	{
		window.scrollBy ( stepX , stepY);
		window.setTimeout ("ws.doScrolling()", ws.dt);
	} else {
		// do something after scrolling
		
		// clean up: 
		ws.startX = null;
		ws.startY = null;
		ws.lastCurX = null;
		ws.lastCurY = null;
		ws.directionIndicatorX = null;
		ws.directionIndicatorY = null;
		
		// debugging:
		//if (debugConsole)  debugConsole.show('status', 'finished');
	}
}
 

WindowScroller.prototype._calculateStepDistance = function (start, cur, target) {
	var step, posOnFunction, y, direction;
	var biggestStep = ( target - start) * 0.04; // 2000
	// if (debugConsole)  debugConsole.show('y', y);

	var distanceToStart = (cur - start);
	if (target - start == 0) {return 0;} // avoid div by zero 

	posOnFunction = distanceToStart / (target - start);
	posOnFunction = posOnFunction * 1.65 * Math.PI + Math.PI/4; 
	y = - Math.cos(posOnFunction);
	// if (debugConsole)  debugConsole.show('posOnFunction', posOnFunction);
	// if (debugConsole)  debugConsole.show('y', y);
	step = ((y + 1) * 0.5) * biggestStep; // move the -cos 1 up
	if (step > 0) direction = +1; else direction = -1;
	step = direction * Math.ceil(Math.abs(step)) ;
	//if (debugConsole)  debugConsole.show('step', step);
	
	return step ;
}



WindowScroller.prototype._determineCurrentScrollPosition = function () {
	var posX;
	var posY;
	
	var w = window;
	
	if (w.pageXOffset) { 
		// non-ie:
		posX = w.pageXOffset;
		posY = w.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollLeft != null) {
		// IE with DOCTYPE set
		posX = document.documentElement.scrollLeft;
		posY = document.documentElement.scrollTop;
	} else if (document.body.scrollLeft != null) {
		// IE without DOCTYPE set
		posX = document.body.scrollLeft;
		posY = document.body.scrollTop;
	} else {
		//debugger;
		w.ws.errors.push( new Error  ("cannot determine scroll position"));
		// alert(document.documentElement.scrollLeft);
	}
	
	this.curX = posX;
	this.curY = posY;
	//if (debugConsole) debugConsole.show('CurX', posX);
	//if (debugConsole) debugConsole.show('CurY', posY);
	
	return [posX, posY];
}






