
bbcjs.trace('<font color="green">scroll.js</font> was included.',2);

var dhtml = new Object();
dhtml.scrolls = {};

/**
 * Scroller Class.
 *
 * @constructor
 *
 * @param wnId ID of div containing scrolling layers (clipped layer).
 * @param lyrId ID of div to scroll, a child of wnId div.
 * @param cntId ID of element containing scrolling content, child of wnId div.
 */
dhtml.Scroller = function (boxId, layerId, containerId)
{
	bbcjs.trace('new dhtml.Scroller()',3);
	
	if (!document.getElementById) return;
	
	this.id = boxId;
	this.box = document.getElementById(boxId);
	this.layer = document.getElementById(layerId);
	this.container = document.getElementById(containerId);
	
	this.speed = 100;
	this.interval = null;
	this.time = new Date().getTime();
	
	this.init();
	dhtml.scrolls[boxId] = this;
}


/**
 * Initialises some properties for the Scroller class.
 */
dhtml.Scroller.prototype.init = function()
{
	bbcjs.trace('dhtml.Scroller.init()', 4);
	
	this.layer.style.visibility = "hidden";
	this.layer.style.top = this.y = 0; 
	this.layer.style.left = this.x = 0;
	this.maxY = (this.layer.offsetHeight - this.box.offsetHeight > 0)? this.layer.offsetHeight - this.box.offsetHeight: 0;
	this.maxX = (this.container.offsetWidth - this.box.offsetWidth > 0)? this.container.offsetWidth - this.box.offsetWidth: 0;
	this.layer.style.visibility = "visible";

	this.ready = true;	
}


/**
 * Convenience function to scroll right at default speed.
 *
 * @param {number} speed Pixels per second (optional, overrides objects own speed property).
 */
dhtml.Scroller.prototype.right = function(speed)
{
	bbcjs.trace('dhtml.scrollRight(' + speed + ')', 4);
	
	var s = speed || this.speed;
	this.start(0, s);
}


/**
 * Convenience function to scroll left at default speed.
 *
 * @param {number} speed Pixels per second (optional, overrides objects own speed property).
 */
dhtml.Scroller.prototype.left = function(speed)
{
	bbcjs.trace('dhtml.scrollLeft(' + speed + ')', 4);
	
	var s = speed || this.speed;
	this.start(180, s);
}


/**
 * Convenience function to scroll up at default speed.
 *
 * @param {number} speed Pixels per second (optional, overrides objects own speed property).
 */
dhtml.Scroller.prototype.up = function(speed)
{
	bbcjs.trace('dhtml.scrollUp(' + speed + ')', 4);

	var s = speed || this.speed;
	this.start(90, s);
}


/**
 * Convenience function to scroll down at default speed.
 *
 * @param {number} speed Pixels per second (optional, overrides objects own speed property).
 */
dhtml.Scroller.prototype.down = function(speed)
{
	bbcjs.trace('dhtml.scrollDown(' + speed + ')', 4);

	var s = speed || this.speed;
	this.start(270, s);
}


/**
 * Initialises multi-directional scrolling properties for Scroller Class.
 *
 * @param {number} degree Direction of scroll.
 * @param {number} speed Pixels per second (optional, overrides objects own speed property).
 */
dhtml.Scroller.prototype.start = function(degree, speed)
{
	bbcjs.trace('dhtml.scroll(' + degree + ',' + speed + ')', 5);
	
	if (!this.ready) return;
	
	var angle, cosine, sine;
	var speed = speed || this.speed;
	
	degree = degree % 360;
	if (degree % 90 == 0)
	{
		cosine = (degree == 0)? -1: (degree == 180)? 1: 0;
		sine = (degree == 90)? 1: (degree == 270)? -1: 0;
	}
	else
	{
		angle = degree * Math.PI/180;
		cosine = -Math.cos(angle);
		sine = Math.sin(angle);
	}
	this.fx = cosine / ( Math.abs(cosine) + Math.abs(sine) );
	this.fy = sine / ( Math.abs(cosine) + Math.abs(sine) );
	this.endX = (degree == 90 || degree == 270)? this.x: (degree < 90 || degree > 270)? -this.maxX: 0;
	this.endY = (degree == 0 || degree == 180)? this.y: (degree < 180)? 0: -this.maxY;
	
	this.stop();
	
	bbcjs.trace('cosine = '+cosine, 3);
	bbcjs.trace('sine = '+sine, 3);
	
	
	this.updateTime();
	this.interval = setInterval("dhtml.scrolls." + this.id + ".take(" + speed + ")", 35);
	
}



/**
 * Stops scrolling for Scroller class.
 */
dhtml.Scroller.prototype.stop = function()
{
	bbcjs.trace('dhtml.Scroller.stop()', 4);
	
	if (!this.ready) return;
	
	if (this.interval) clearInterval(this.interval);
	this.interval = null;
}



/**
 * Called by scroll() to acheive the scrolling effect.
 *
 * @param {number} speed How fast to scroll (pixels per second).
 */
dhtml.Scroller.prototype.take = function(speed)
{
	bbcjs.trace('dhtml.Scroller.take(' + speed + ')', 6);
	
	var elapsed = this.updateTime();
	var distance = elapsed/1000 * speed;
	
	if (distance > 0)
	{
		var x = this.x + (this.fx * distance);
		var y = this.y + (this.fy * distance);
		if (this.fx == 0 || this.fy == 0)
		{ // for horizontal or vertical scrolling
			if ( ( this.fx == -1 && x > -this.maxX ) || ( this.fx == 1 && x < 0 ) || ( this.fy == -1 && y > -this.maxY ) || ( this.fy == 1 && y < 0 ) )
			{
				this.shiftTo(x, y);
			} 
			else
			{
				this.shiftTo(this.endX, this.endY);
				this.stop();
			}
		} 
		else
		{ // for scrolling at an angle (stop when reach end on one axis)
			if ( ( this.fx < 0 && x >= -this.maxX && this.fy < 0 && y >= -this.maxY ) || ( this.fx > 0 && x <= 0 && this.fy > 0 && y <= 0 ) || ( this.fx < 0 && x >= -this.maxX && this.fy > 0 && y <= 0 ) || ( this.fx > 0 && x <= 0 && this.fy < 0 && y >= -this.maxY ) )
			{
				this.shiftTo(x, y);
			}
			else
			{
				this.stop();
			}
		}
	}
}


/**
 * Basic function to recast display coordinates of a Scroller object.
 *
 * @param {number} x The X coordinate
 * @param {number} y The Y coordinate
 */
dhtml.Scroller.prototype.shiftTo = function(x, y)
{
	bbcjs.trace('dhtml.Scroller.shiftTo(' + x + ',' + y + ')', 6);
	
	this.layer.style.left = (this.x = x) + "px"; 
	this.layer.style.top = (this.y = y) + "px";
}


/**
 * Sets time property to current time, returns time elapsed since last update.
 */
dhtml.Scroller.prototype.updateTime = function()
{
	bbcjs.trace('dhtml.updateTime()', 6);
	
	var time = new Date().getTime();
	var elapsed = time - this.time;

	this.time = time;
	return elapsed;
}
