/*
    Copyright (C) 2005  Zachary J. Medico  <zmedico@yahoo.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    
    This class floats an absolutely positioned element up and down the page as the users scrolls vertically.
    It uses functions getObj() and getPageYOffset() from ObjectDetection.js in order to work around browser differences.
    
    Example of usage:
    
	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
	<html>
	<head>
	<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
	<title></title>
	<script type="text/javascript" src="VerticalFloater.js"></script>
	</head>
	<body>
	<div id="floatingElementid" style="position: absolute; top: 20; left: 20;">
	Floating Element
	</div>
	<script type="text/javascript" >
	<!--
	window.floater = new VerticalFloater('floater','floatingElementid');
	floater.setElementId('floatingElement');
	floater.start();
	//-->
	</script>
	<p>
	<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
	<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
	<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
	<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
	</p>
	</body>
	</html>

*/

/*
Constructor
	windowPropertyName	The name of the window's property that references this object.
	elementid			The unique id property of the element whose position will be animated.
	parentWindow		The window that the element belongs to.  If undefined the current window will be used.
*/
function VerticalFloater(windowPropertyName, elementid, parentWindow)
{
	this.window = parentWindow || window;
	this.windowPropertyName = windowPropertyName;
	var temp=new getObj(this.window, elementid);
	this.element = temp.obj;
	this.style = temp.style;
	delete temp;
	
	
	
	// Factor used to caculate step size as a function of the total distance to travel.   0 < stepFactor <= 1
	this.stepFactor=0.2;
	
	// Maximum change in step size (also known as acceleration).
	this.maxAccel=2;
	
	// Time in milliseconds to sleep between iterations while approaching equilibrium. See window.setInterval
	// Default is 30 times per second

	this.animationInterval=1000/30;

	

	// Time in milliseconds for polling the viewportYOffset

	this.pollInterval=1000/3;

	

	// This shifts between pollInterval and animationInterval as necessary
	this.interval=this.pollInterval;

	
	this.previousScrollTop = getPageYOffset(this.window);
	this.difference=0;
	
	if (this.style.top){
		topString = this.style.top;
	
		// remove the 'px' pixels suffix if necessary
		if ( topString.substring(topString.length-2,topString.length) == 'px' )
			this.viewportYOffset = parseInt(topString.substring(0,topString.length-2));
		else
			this.viewportYOffset = parseInt(topString);
		this.currentOffset = this.viewportYOffset;
	}
	else{
		this.currentOffset = this.viewportYOffset = 0;
	}
}

VerticalFloater.prototype = new Object;

VerticalFloater.prototype.start=function()
{
	this.timerid = this.window.setInterval( 'window.'+ this.windowPropertyName + '.step()', this.interval );
}

/*
Stop the animation and move the floater to a distance of this.viewportYOffset from the top of the page.
*/
VerticalFloater.prototype.stop=function()
{
	if (this.timerid)
	{
		this.window.clearInterval(this.timerid);
		delete this.timerid;
		this.style.top = this.viewportYOffset +'px';
	}
}

/*
Update the interval
*/
VerticalFloater.prototype.setInterval=function(interval)
{
	if (this.interval!=interval && interval!=null && interval!=undefined )
	{
		this.interval=interval || this.interval;
		
		if (this.timerid)
		{
			this.window.clearInterval(this.timerid);
			this.timerid = this.window.setInterval( 'window.'+ this.windowPropertyName + '.step()', this.interval );
		}
	}
}

/*

This is where the animation occurs.  This is scheduled to be called repeatedly by the Window.setInterval() method.
This interval is this.pollInterval when no animation is happening and this.animationInterval during animation
*/
VerticalFloater.prototype.step = function()
{
	// wait until the user stops scrolling to move the element
	// Otherwise there is a "jumpy" effect if the user scrolls slowly
	if (getPageYOffset(this.window)==this.previousScrollTop)
	{
		this.destination = getPageYOffset(this.window) + this.viewportYOffset;
		this.difference = this.currentOffset - this.destination;
		
		if (this.difference!=0 && this.difference==this.previousDifference)
		{
			// boundary condition which allows it to reach equilibrium
			this.currentOffset-=this.difference;
			this.style.top = this.currentOffset +'px';
		}
		else if (this.difference!=0)
		{

			if ( this.interval!=this.animationInterval)
				this.setInterval(this.animationInterval);
			
			this.previousStep=this.currentStep;
			this.currentStep=Math.abs(Math.round(this.stepFactor*this.difference));
			
			if ( (this.currentStep - this.previousStep) > this.maxAccel )
				this.currentStep=this.previousStep+this.maxAccel;
			
			if (this.difference>0)

				this.currentOffset -= this.currentStep;
			else
				this.currentOffset += this.currentStep;
			this.style.top = this.currentOffset +'px';
		}
		this.previousDifference = this.difference;

	}
	this.previousScrollTop = getPageYOffset(this.window);
	
	if ( this.difference==0 && this.interval!=this.pollInterval )
		this.setInterval(this.pollInterval);
}

/*
Equlibrium distance (integer pixels) of the top of the floating element from the top of the window's viewport
This property is set automatically by the setElementId() method to the floating element's "top" style property, if it exists
*/
VerticalFloater.prototype.setViewportYOffset=function(viewportYOffset)
{
	this.viewportYOffset = viewportYOffset || 0;
	this.currentOffset = this.viewportYOffset;
}

VerticalFloater.prototype.setFps=function(fps)
{
	this.interval=1000/fps;
}
