/* 
	TODO: 
	
	1: Build in other functionality:
		Continuous scrolling while mouse down depressed. 
		Tidy on / off.
	2: Build in functionality for up down scrolling, positioning of blocks in vertical / horizontal rows or blocks
		Maybe something like visible blocks 1 x 4, or 4 x 1 or 8 x 8.
		If smooth scroll on how many blocks to scroll at a time 1, 2, 4 etc.
		Diagonal Movement???
*/		

/**
 * The Scroller class
 * @author Matthew Haynes
 * @constructor
 * @param opts Pass an object with properties through to the class.
**/

function Scroller (opts) {
	this.init(opts);
}

Scroller.prototype = {

	init : function(opts) {
		
		// Set options
		// NB: Could set some default values here.
		this.options = {}

		if (opts) {
			Common.setOptions(this, opts);
		}
		
		// Get Parent
		var frame = document.getElementById(this.options.parentElem);
		
		this.positionFrame(frame);

		// Get all child elements with "blocks" as classname.
		this.blocks = Common.getElementsByClass(frame, "*", "block");
		
		this.positionBlocks(this.blocks);
		
				
	},
	
	checkEnd : function(direction) {
	
		switch(direction) {
			case 1:
				if (this.blocks[this.blocks.length -1].leftValue < (this.scrollerWidth * 2) - this.options.blockWidth - this.options.blockSpacing) {
					this.move(direction, thisEl);
				} else {
					this.canMove = true;
				}
				break;

			case -1:
				if (this.blocks[this.blocks.length -1].leftValue > this.scrollerWidth - this.options.blockWidth) {
				 	this.move(direction, thisEl);
				} else {
					this.canMove = true;
				}

				break;
		}		
	},

	/***
	* checkVisibility: Turn off visibility of the block if it is outside the visible area of the scroller. This means that a user who uses the tab key for navigation will not messup the scroller by tabbing onto an off screen block.
	***/
	checkVisibility : function(thisEl) {

		if (thisEl.leftValue <= (0 - this.options.blockWidth - this.options.blockSpacing) || thisEl.leftValue > this.scrollerWidth) {
			thisEl.style.visibility = "hidden";
		} else if (thisEl.leftValue > 0 || thisEl.leftValue < this.scrollerWidth) {
			thisEl.style.visibility = "visible";
		}
	},

	/***
	* checkWrap: Prepare to move function, works out if a block has to wrap left or right
	* @direction: Direction of travel. 1 or -1, for right or left.
	***/
	checkWrap : function(direction, thisEl) {

		// Check direction
		switch(direction) {

			case 1:
				
				// If we're too far right then wrap to start
				// This should be (block width + clock spacing) * (no. of blocks - 1)
				if (thisEl.leftValue >= (this.options.blockWidth + this.options.blockSpacing) * (this.blocks.length -1)) {//(this.scrollerWidth * 2) - this.options.blockWidth - this.options.blockSpacing) {
								
					thisEl.leftValue = 0 - this.options.blockWidth - this.options.blockSpacing ;
					//thisEl.remLeftValue = thisEl.leftValue;
					thisEl.style.left = thisEl.leftValue + "px";
				}
	
				break;

			case -1:

				// If we're too far left then wrap to end
				if (thisEl.leftValue < 0 - this.options.blockWidth - this.options.blockSpacing) {
				
					thisEl.leftValue = ((this.options.blockWidth + this.options.blockSpacing) * (this.blocks.length -2));
					thisEl.style.left = thisEl.leftValue + "px";
				}
				break;
		}
	},	

	/***
	* move: Move functionality, moves this div left or right, argument i is the number of this object in the blocks array, needed for setTimeout
	* @direction: Direction of travel. 1 or -1, for right or left.
	***/
	move : function(direction, thisEl) {

		if (thisEl.moved >= this.options.blockWidth) {

			thisEl.leftValue = thisEl.remLeftValue + ((this.options.blockWidth + this.options.blockSpacing) * direction);
			thisEl.style.left = thisEl.leftValue + "px";
			
			thisEl.moved = 0;
			
			
			if (thisEl == this.blocks[this.blocks.length - 1]) {
				this.canMove = true;
			}

		} else {

			// Move this div
			thisEl.leftValue += (this.options.scrollDist * direction);
			thisEl.style.left = thisEl.leftValue + "px";

			this.checkVisibility(thisEl);
			
			// Update
			thisEl.moved += this.options.scrollDist;

			if (this.options.smoothScroll == true) {
				// And again..
				window.setTimeout(function () { s.move(direction,thisEl); }, this.options.scrollSpeed);
			}
		}

	},

	positionBlocks : function(blocks) {

		// Loop through blocks and position in a line

		for (var i=0;i<blocks.length;i++) {
		
			thisEl = blocks[i];

			var styles = {
				position:"absolute",
				top:"0",
				left:(this.options.blockWidth + this.options.blockSpacing) * i + "px"
			}

			Common.setStyles(thisEl, styles);

			// Set some properties
			thisEl.leftValue = ((this.options.blockWidth * i) + (this.options.blockSpacing * i));
			thisEl.moved = 0;
			this.canMove = true;
			this.checkVisibility(thisEl);

		}

	},

	positionFrame : function(frame) {

			// Style the frame

			// How wide?
			// Scroller width should be! (no of visible blocks * blocks width) + (no of visible blocks * block spacing)
			this.scrollerWidth = ((this.options.blockWidth * this.options.viewableX) + (this.options.blockSpacing * (this.options.viewableX - 1)));// + 2);

			// Set CSS
			var styles = {
				position:"relative",
				overflow:"hidden"
			}

			Common.setStyles(frame, styles);
			
	},

	triggerMove : function(direction) {

		if (this.canMove == true) {
		
			if (this.options.smoothScroll == true) {
				this.canMove = false;
			}
			
			for (var i=0;i < this.blocks.length;i++) {
			
				thisEl = this.blocks[i];
		
				// Check Wrapping
				if (this.options.wrap == true) {
					this.checkWrap(direction, thisEl);
					// Remember the left value before move starts
					if (thisEl.moved == 0) {thisEl.remLeftValue = thisEl.leftValue;}
					//thisEl.remLeftValue = thisEl.leftValue;
					this.move(direction, thisEl);
				} else {
					thisEl.remLeftValue = thisEl.leftValue;
					this.checkEnd(direction)
				}
			}
	    }	
	}
}
