/*  Copyright Nick Allan 2007  |  www.pjweb.co.uk
 * -----------------------------------------------------------
 *
 * JavaScript Scroller Class v1.0
 *
 * 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, width) 
		{
			this.i = i;
			this.id = id;
			this.content = content;
			this.width = width;

			this.obj = document.getElementById(this.id);

		}


/* CLASS TO HOLD DATA ABOUT SCROLLER */

	// Constructor
		function Scroller(instance, div, continuous, speed, ltr)
		{
			// 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?
				this.rtl = ltr ? 0 : 1;

			// holds child objects
				this.children = new Array();

			// holds the current child index
				this.current = 0;

			// holds the total width of all the children
				this.width_of_children = 0;

			// some browsers don't work left to right so force t'other way
				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, width) 
		{
			var i = this.children.length;

			// must have width
				if (!width)
				{
					alert("You must set width 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, width);

			// 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.width_of_children+= width;
		}

	// 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
				var child = document.getElementById(this.children[k].id); 
				var offset = this.rtl ? child.style.left : child.style.right;
				offset = parseInt(offset ? offset : 0);
				offset+= child.offsetWidth;

			// assume visible
				child.style.visibility = "visible";

			// set width if width specified
				if (this.width) child.style.width = this.width + "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.rtl)
							child.style.left = offset + "px";
						else
							child.style.right = offset + "px";

					

					// assume visible
						child.style.visibility = "visible"; // child.style.visibility = (offset <= container.offsetWidth) ? "visible" : "hidden";

					// work out the position of the next child
						offset+= child.offsetWidth;
				}

		}

	// 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 width of container
						var width_container = container.offsetWidth;

				// if there's only one child create copy/copies of child if required				
					if (this.children.length == 1)
					{
						// get width of only child
							var width_child = child.offsetWidth;

						// if the child is wider than the container, create one copy
							if (width_container <= width_child)
								n = 1;
						// create enough copies to fill container
							else
								var n = Math.ceil(width_container / width_child);

						// create the copies
							while (n-- > 0) this.addChild(this.children[0].content, this.children[0].width);
					}
				// create copy/copies of all the children if required
					else
					{
						// get width of children
							var width_children = this.width_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 (width_children < width_container)
							{
								// copy all the children
									for (i = 0; i < n; i++) this.addChild(this.children[i].content, this.children[i].width);

								// get new width of children
									width_children = this.width_of_children;
							}
					}
				}

			// position the first child
				if (this.rtl)
					child.style.left = showToBegin ? "0px" : (container.offsetWidth + "px");
				else
					child.style.right = showToBegin ? "0px" : (container.offsetWidth + "px");

			// position children based on first child, assuming first child is already positioned correctly
				this.positionChildren();

			// start scrolling
				this.doScroll();
		}

	// method for ease of use
		Scroller.prototype.startInView = function () 
		{
			this.start(1);
		}

	// method that performs the scrolling
		Scroller.prototype.doScroll = function() 
		{
			// get the current child
				var i = this.current;
				var child = document.getElementById(this.children[i].id); 

			// get width of child
				var child_width = child.offsetWidth;

			// get current child's position
				var child_pos = this.rtl ? parseInt(child.style.left) : parseInt(child.style.right);
				child_pos = child_pos ? child_pos : 0;

			// get container width
				var container = document.getElementById(this.container);
				var container_width = container.offsetWidth;

			// if the current child is out of view
				if (child_pos < (0 - child_width))
				{
					// reposition current child to the back of the queue
						if (this.rtl)
							child.style.left = Math.max(this.width_of_children - child_width, container_width) + "px";
						else
							child.style.right = Math.max(this.width_of_children - child_width, container_width) + "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); 
						child_width = child.offsetWidth;

					// get new child's position
						var child_pos = this.rtl ? parseInt(child.style.left) : parseInt(child.style.right);
						child_pos = child_pos ? child_pos : 0;
				}

			// move current child
				if (this.rtl)
					child.style.left = (child_pos - 2) + "px";
				else
					child.style.right = (child_pos - 2) + "px";

			// now the current child has been moved, position the rest
				this.positionChildren(i);

			// recurse
				setTimeout(this.instance + ".doScroll()",Math.ceil(1000 / this.speed));
		}
