/*  Copyright Nick Allan 2007  |  www.pjweb.co.uk
 * -----------------------------------------------------------
 *
 * JavaScript Scroller Class v1.1
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 */



/* CLASS TO HOLD DATA ABOUT SCROLLER CONTENT */

	// Constructor and only method
		function ScrollerContent(i, id, content, size) 
		{
			this.i = i;
			this.id = id;
			this.content = content;
			this.size = size; // width or height, dependent on whether the scroller is vertical or horizontal

			this.obj = document.getElementById(this.id);

		}


/* CLASS TO HOLD DATA ABOUT SCROLLER */

	// Constructor
		function Scroller(instance, div, continuous, speed, ltr, is_vertical, pause)
		{
			// name of the instance of the class (for the javascript timer to call itself again)
				this.instance = instance;

			// id of div to hold the scroller
				this.wrapper = div;

			// speed of scrolling - values above 50 don't really make much difference
				this.speed = speed;

			// boolean - continuous scrolling
				this.continuous = continuous;

			// boolean - right to left / bottom to top
				this.rtl = ltr ? 0 : 1;

			// boolean - right to left / bottom to top
				this.is_vertical = parseInt(is_vertical);

			// milliseconds to pause between each item
				this.pause = parseInt(pause);

			// holds child objects
				this.children = new Array();

			// holds the current child index
				this.current = 0;

			// holds the total size of all the children
				this.size_of_children = 0;

			// some browsers don't work left to right so force t'other way
				if (!this.is_vertical) this.forceRTL();

			// create scroller container div - gets dynamically created inside the wrapper
				this.container = this.wrapper + "_container";
				var container = document.createElement("DIV");
				container.setAttribute("id",this.container);

				var wrapper = document.getElementById(this.wrapper);

				if (wrapper && wrapper.appendChild)
					wrapper.appendChild(container);
				else
					alert("Couldn't set up scroller correctly!");
		}

	// method to force right to left scrolling if certain browsers are detected
		Scroller.prototype.forceRTL = function () 
		{
			var ua = navigator.userAgent.toLowerCase();
			
			// firefox mac
				if (ua.match(/firefox/) && ua.match(/mac/)) this.rtl = true;
			
			// netscape
				if (ua.match(/netscape/)) this.rtl = true;
		}

	// method to add a child to the scrolling ie. something that is scrolled
		Scroller.prototype.addChild = function (content, size) 
		{
			var i = this.children.length;

			// must have size
				if (!size)
				{
					alert("You must set width/height of children!");
					return;
				}
			
			// dynamically create child div
				var child = document.createElement("DIV");

			// create new child
				this.children[i] = new ScrollerContent(i, this.container + "_child" + i, content, size);

			// set properties and HTML of child div
				child.setAttribute("id",this.children[i].id);
				child.innerHTML = content;

			// add the child div to the parent div
				var container = document.getElementById(this.container);
				if (container && container.appendChild) container.appendChild(child);

			// work out how wide all the children are
				this.size_of_children+= size;
		}

	// method to position all the children relative to the child passed as a parameter
	// (assumes child passed as parameter is already positioned
		Scroller.prototype.positionChildren = function (k) 
		{
			// if no parameter, set to first child
				if (!k) k = 0;

			// get container
				var container = document.getElementById(this.container);

			// get number of children
				var n = this.children.length;

			// get current child and current offset left/right/top/bottom
				var child = document.getElementById(this.children[k].id);
				
				if (!this.is_vertical)
				{
					var offset = this.rtl ? child.style.left : child.style.right;
					offset = parseInt(offset ? offset : 0);
					offset+= child.offsetWidth;
				}
				else
				{
					var offset = this.rtl ? child.style.top : child.style.bottom;
					offset = parseInt(offset ? offset : 0);
					offset+= child.offsetHeight;
				}

			// assume visible
				child.style.visibility = "visible";

			// set size if size specified
//				if (this.size) child.style.size = this.size + "px";
				if (this.children[k].size)
				{
					if (!this.is_vertical)
						child.style.width = this.children[k].size + "px";
					else
						child.style.height = this.children[k].size + "px";
				}

			// loop through children and position them based on previous child's position
				var i = n;
				
				while (--i > 0)
				{
					// get next child index
						k = (k + 1) % n;

					// get child
						var child = document.getElementById(this.children[k].id);

					// position child
						if (!this.is_vertical)
						{
							if (this.rtl)
								child.style.left = offset + "px";
							else
								child.style.right = offset + "px";
						}
						else
						{
							if (this.rtl)
								child.style.top = offset + "px";
							else
								child.style.bottom = offset + "px";
						}

					

					// assume visible
						child.style.visibility = "visible"; // child.style.visibility = (offset <= container.offsetWidth) ? "visible" : "hidden";

					// work out the position of the next child
						if (!this.is_vertical)
							offset+= child.offsetWidth;
						else
							offset+= child.offsetHeight;
				}

		}

	// method that starts the scrolling process
	// it works out if any more copies of the children need to be created
	// it positions the first child
		Scroller.prototype.start = function (showToBegin) 
		{
			// if no children then quit
				if (!this.children.length) return;

			// get parent and first child
				var container = document.getElementById(this.container);
				var child = document.getElementById(this.children[0].id); 

			// if we want continuous looping, create copy/copies of first child(ren) if required
				if (this.continuous)
				{
					// get size of container
						if (!this.is_vertical)
							var size_container = container.offsetWidth;
						else
							var size_container = container.offsetHeight;

				// if there's only one child create copy/copies of child if required				
					if (this.children.length == 1)
					{
						// get size of only child
							if (!this.is_vertical)
								var size_child = child.offsetWidth;
							else
								var size_child = child.offsetHeight;

						// if the child is wider than the container, create one copy
							if (size_container <= size_child)
								n = 1;
						// create enough copies to fill container
							else
								var n = Math.ceil(size_container / size_child);

						// create the copies
							while (n-- > 0) this.addChild(this.children[0].content, this.children[0].size);
					}
				// create copy/copies of all the children if required
					else
					{
						// get size of children
							var size_children = this.size_of_children;

						// need to remember original length of children
							var n = this.children.length;

						// if the children aren't wide enough, create copies of current children
							while (size_children < size_container)
							{
								// copy all the children
									for (i = 0; i < n; i++) this.addChild(this.children[i].content, this.children[i].size);

								// get new size of children
									size_children = this.size_of_children;
							}
					}
				}

			// position the first child
				if (!this.is_vertical)
				{
					if (this.rtl)
						child.style.left = showToBegin ? "0px" : (container.offsetWidth + "px");
					else
						child.style.right = showToBegin ? "0px" : (container.offsetWidth + "px");
				}
				else
				{
					if (this.rtl)
						child.style.top = showToBegin ? "0px" : (container.offsetHeight + "px");
					else
						child.style.bottom = showToBegin ? "0px" : (container.offsetHeight + "px");
				}

			// position children based on first child, assuming first child is already positioned correctly
				this.positionChildren();

			// start scrolling
				this.doScroll(1);
		}

	// method for ease of use
		Scroller.prototype.startInView = function () 
		{
			this.start(1);
		}

	// method that performs the scrolling
		Scroller.prototype.doScroll = function(do_pause) 
		{
			do_pause = do_pause ? 1 : 0;

			// get the current child
				var i = this.current;
				var child = document.getElementById(this.children[i].id); 

			// get size of child
				if (!this.is_vertical)
					var child_size = child.offsetWidth;
				else
					var child_size = child.offsetHeight;

			// get current child's position
				if (!this.is_vertical)
					var child_pos = this.rtl ? parseInt(child.style.left) : parseInt(child.style.right);
				else
					var child_pos = this.rtl ? parseInt(child.style.top) : parseInt(child.style.bottom);

				child_pos = child_pos ? child_pos : 0;

			// get container size
				var container = document.getElementById(this.container);

				if (!this.is_vertical)
					var container_size = container.offsetWidth;
				else
					var container_size = container.offsetHeight;

			// if the current child is out of view
				if (child_pos < (0 - child_size))
				{
					// reposition current child to the back of the queue
						if (!this.is_vertical)
						{
							if (this.rtl)
								child.style.left = Math.max(this.size_of_children - child_size, container_size) + "px";
							else
								child.style.right = Math.max(this.size_of_children - child_size, container_size) + "px";
						}
						else
						{
							if (this.rtl)
								child.style.top = Math.max(this.size_of_children - child_size, container_size) + "px";
							else
								child.style.bottom = Math.max(this.size_of_children - child_size, container_size) + "px";
						}

					// select next child
						this.current = (this.current + 1) % this.children.length;
						i = this.current;

					// get new child
						child = document.getElementById(this.children[i].id);

						if (!this.is_vertical)
							child_size = child.offsetWidth;
						else
							child_size = child.offsetHeight;

					// get new child's position
						if (!this.is_vertical)
							var child_pos = this.rtl ? parseInt(child.style.left) : parseInt(child.style.right);
						else
							var child_pos = this.rtl ? parseInt(child.style.top) : parseInt(child.style.bottom);

						child_pos = child_pos ? child_pos : 0;

					// we now need to do the pause
						do_pause = true;
				}

			// move current child
				child_pos-= 2;

				if (!this.is_vertical)
				{
					if (this.rtl)
						child.style.left = child_pos + "px";
					else
						child.style.right = child_pos + "px";
				}
				else
				{
					if (this.rtl)
						child.style.top = child_pos + "px";
					else
						child.style.bottom = child_pos + "px";
				}

			// now the current child has been moved, position the rest
				this.positionChildren(i);

			// recurse
				var speed = Math.ceil(1000 / this.speed);
				if (this.pause > 0 && do_pause) speed = this.pause;


				setTimeout(this.instance + ".doScroll()",speed);
		}
