/**
 * Slider
 * @author Scott Doxey
 */

var Slider = {
	
	object: null,
	inner: null,
	speed: 10,
	dir: 'ltr', // utd
	page: 0,
	pages: 0,
	width: 0,
	height: 0,
	visible: 0,
	scroll_pos: 0,
	scroll_set_x: Array(),
	scroll_set_y: Array(),
	
	/**
	 * Slider.init
	 * Initializes the Slider class on an object. Also resets any variables on an existing slider object.
	 * @method boolean Slider.init(object object);
	 * @param object object
	 * @return boolean
	 * @example Slider.init(document.getElementById('slider'));
	 * @author Scott Doxey
	 */
	
	init: function(object) {
		
		if (object) { this.object = object; }
		this.inner = this.fetchNodes(this.object)[0];
		var inner_nodes = this.fetchNodes(this.inner);
		
		this.width = 0;
		this.height = 0;
		this.scroll_set_x = Array();
		this.scroll_set_y = Array();
		
		this.scroll_set_x.push(0);
		this.scroll_set_y.push(0);
		
		for (var i = 0, length = inner_nodes.length; i < length; i++) {
			if (this.getStyle(inner_nodes[i], 'display') == 'none') { continue; }
			this.width += this.offsetWidth(inner_nodes[i]);
			this.height += this.offsetHeight(inner_nodes[i]);
			if (!this.visible && this.width > this.offsetWidth(this.object)) { this.visible = this.scroll_set_x.length -1; }
			if (!this.visible && this.height > this.offsetHeight(this.object)) { this.visible = this.scroll_set_y.length -1; }
			if (i < length-1) { this.scroll_set_x.push(this.width); }
			if (i < length-1) { this.scroll_set_y.push(this.height); }
		}
		
		this.page = 1;
		if (this.dir == 'ltr') { this.pages = Math.ceil(this.scroll_set_x.length / this.visible); }
		else if (this.dir == 'utd') { this.pages = Math.ceil(this.scroll_set_y.length / this.visible); }
		
		this.object.style.overflow = 'hidden';
		this.object.style.position = 'relative';
		
		this.object.style.width = this.offsetWidth(inner_nodes[0]) + 'px';
		
		clearInterval(this.inner.interval);
		
		this.inner.style.position = 'absolute';
		
		if (this.dir == 'ltr') {
			this.inner.style.width = this.width + 'px';
			this.inner.style.height = this.offsetHeight(inner_nodes[0]) + 'px';
		} else if (this.dir == 'utd') {
			this.inner.style.width = this.offsetWidth(inner_nodes[0]) + 'px';
			this.inner.style.height = this.height + 'px';
		}
		
		this.inner.style.left = '0px';
		this.inner.style.top = '0px';
		
		return false;
		
	},
	
	/**
	 * Slider.left
	 * Moves the slider left or to a specific page.
	 * @method boolean Slider.left([integer num]);
	 * @param integer num
	 * @return boolean
	 * @example Slider.left();
	 * @example Slider.left(2);
	 * @author Scott Doxey
	 */
	
	left: function(num) {
		
		if (this.object.style.height == 'auto') { return false; }
		
		if (this.dir != 'ltr') { this.dir = 'ltr'; this.init(); }
		
		if (num) { pos = this.visible * (num -1); } else { pos = this.scroll_pos - this.visible; }
		
		if (typeof(this.scroll_set_x[pos]) == 'number') { this.scroll_pos = pos; }
		
		this.page = (this.scroll_pos / this.visible) +1;
		
		if (this.speed) { this.move(this.inner, -this.scroll_set_x[this.scroll_pos], null, this.speed); }
		else { this.inner.style.left = -this.scroll_set_x[this.scroll_pos] + 'px'; }
		
		return false;
		
	},
	
	/**
	 * Slider.right
	 * Moves the slider right or to a specific page.
	 * @method boolean Slider.right([integer num]);
	 * @param integer num
	 * @return boolean
	 * @example Slider.right();
	 * @example Slider.right(2);
	 * @author Scott Doxey
	 */
	
	right: function(num) {
		
		if (this.object.style.height == 'auto') { return false; }
		
		if (this.dir != 'ltr') { this.dir = 'ltr'; this.init(); }
		
		if (num) { pos = this.visible * (num -1); } else { pos = this.scroll_pos + this.visible; }
		
		if (typeof(this.scroll_set_x[pos]) == 'number') { this.scroll_pos = pos; }
		
		this.page = (this.scroll_pos / this.visible) +1;
		
		if (this.speed) { this.move(this.inner, -this.scroll_set_x[this.scroll_pos], null, this.speed); }
		else { this.inner.style.left = -this.scroll_set_x[this.scroll_pos] + 'px'; }
		
		return false;
		
	},
	
	/**
	 * Slider.up
	 * Moves the slider up or to a specific page.
	 * @method boolean Slider.up([integer num]);
	 * @param integer num
	 * @return boolean
	 * @example Slider.up();
	 * @example Slider.up(2);
	 * @author Scott Doxey
	 */
	
	up: function(num) {
		
		if (this.object.style.height == 'auto') { return false; }
		
		if (this.dir != 'utd') { this.dir = 'utd'; this.init(); }
		
		if (num) { pos = this.visible * (num -1); } else { pos = this.scroll_pos + this.visible; }
		
		if (typeof(this.scroll_set_y[pos]) == 'number') { this.scroll_pos = pos; }
		
		this.page = (this.scroll_pos / this.visible) +1;
		
		if (this.speed) { this.move(this.inner, null, -this.scroll_set_y[this.scroll_pos], this.speed); }
		else { this.inner.style.top = -this.scroll_set_y[this.scroll_pos] + 'px'; }
		
		return false;
		
	},
	
	/**
	 * Slider.down
	 * Moves the slider down or to a specific page.
	 * @method boolean Slider.down([integer num]);
	 * @param integer num
	 * @return boolean
	 * @example Slider.down();
	 * @example Slider.down(2);
	 * @author Scott Doxey
	 */
	
	down: function(num) {
		
		if (this.object.style.height == 'auto') { return false; }
		
		if (this.dir != 'utd') { this.dir = 'utd'; this.init(); }
		
		if (num) { pos = this.visible * (num -1); } else { pos = this.scroll_pos - this.visible; }
		
		if (typeof(this.scroll_set_y[pos]) == 'number') { this.scroll_pos = pos; }
		
		this.page = (this.scroll_pos / this.visible) +1;
		
		if (this.speed) { this.move(this.inner, null, -this.scroll_set_y[this.scroll_pos], this.speed); }
		else { this.inner.style.top = -this.scroll_set_y[this.scroll_pos] + 'px'; }
		
		return false;
		
	},
	
	/**
	 * Slider.toggle
	 * Toggles the view to display some or all of the items within the slider.
	 * @method boolean Slider.toggle();
	 * @return boolean
	 * @example Slider.toggle();
	 * @author Scott Doxey
	 */
	
	toggle: function() {
	
		if (this.inner.interval) { clearInterval(this.inner.interval); }
		
		var inner_nodes = this.fetchNodes(this.inner);
		
		if (this.object.style.height != 'auto') {
			
			this.object.style.height = 'auto';
			this.inner.style.position = 'relative';
			this.inner.style.width = 'auto';
			this.inner.style.height = this.height + 'px';
			this.inner.style.left = '0px';
			this.inner.style.top = '0px';
			this.page = null;
			
		} else {
		
			this.object.style.height = this.offsetHeight(inner_nodes[0]) + 'px';
			this.inner.style.position = 'absolute';
			
			if (this.dir == 'ltr') {
				this.inner.style.width = this.width + 'px';
				this.inner.style.height = this.offsetHeight(inner_nodes[0]) + 'px';
				this.inner.style.left = -this.scroll_set_x[this.scroll_pos] + 'px';
			} else if (this.dir == 'utd') {
				this.inner.style.width = this.offsetWidth(inner_nodes[0]) + 'px';
				this.inner.style.height = this.height + 'px';
				this.inner.style.top = -this.scroll_set_y[this.scroll_pos] + 'px';
			}
			
			this.page = (this.scroll_pos / this.visible) +1;
			
		}
		
		return false;
		
	},
	
	/**
	 * Slider.fetchNodes
	 * Fetches all of the children nodes (element nodes) of a certain object.
	 * @method array Slider.fetchNodes(object object);
	 * @param object object
	 * @return array
	 * @example Slider.fetchNodes(div);
	 * @author Scott Doxey
	 */
	
	fetchNodes: function(object) {
		
		var array = Array();
		var nodes = object.childNodes;
		
		for (var i = 0, length = nodes.length; i < length; i++) {
			if (nodes[i].nodeType == 1) { array.push(nodes[i]); }
		}
		
		return array;
		
	},
	
	/**
	 * Slider.offsetWidth
	 * Captures the true offsetWidth of an object. Note: Margin, padding, and border-width must be set to an integer or it will error in IE.
	 * @method integer Slider.offsetWidth(object object);
	 * @param object object
	 * @return integer
	 * @example Slider.offsetWidth(div);
	 * @author Scott Doxey
	 */
	
	offsetWidth: function(object) {
		var width = 0;
		var attributes = Array('width', 'padding-left', 'padding-right', 'border-left-width', 'border-right-width', 'margin-left', 'margin-right');
		for (var i = 0, length = attributes.length; i < length; i++) { width += Number(this.getStyle(object, attributes[i])); }
		return width;
	},
	
	/**
	 * Slider.offsetHeight
	 * Captures the true offsetHeight of an object. Note: Margin, padding, and border-width must be set to an integer or it will error in IE.
	 * @method integer Slider.offsetHeight(object object);
	 * @param object object
	 * @return integer
	 * @example Slider.offsetHeight(div);
	 * @author Scott Doxey
	 */
	
	offsetHeight: function(object) {
		var height = 0;
		var attributes = Array('height', 'padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width', 'margin-top', 'margin-bottom');
		for (var i = 0, length = attributes.length; i < length; i++) { height += Number(this.getStyle(object, attributes[i])); }
		return height;
	},
	
	/**
	 * Slider.move
	 * Moves the slider's inner object (or any object) from left to right.
	 * @method boolean Slider.move(object object, integer end_x, integer end_y, integer speed);
	 * @param object object
	 * @param integer end_x
	 * @param integer end_y
	 * @param integer speed
	 * @return boolean
	 * @example Slider.move(div, 0, 200, 25);
	 * @author Scott Doxey
	 */
	
	move: function(object, end_x, end_y, speed) {
		
		start_x = object.offsetLeft;
		start_y = object.offsetTop;
		
		if (typeof(end_x) != 'number') { end_x = start_x; }
		if (typeof(end_y) != 'number') { end_y = start_y; }
		
		if (object.interval) { clearInterval(object.interval); }
		
		object.interval = setInterval(function() {
			
			start_x += (end_x - start_x) / speed;
			start_y += (end_y - start_y) / speed;
			
			object.style.left = start_x + 'px';
			object.style.top = start_y + 'px';
			
			if (Math.round(start_x) == end_x && Math.round(start_y) == end_y) {
				object.style.left = end_x + 'px';
				object.style.top = end_y + 'px';
				clearInterval(object.interval);
			}
			
		}, 1);
		
		return false;
		
	},
	
	/**
	 * Slider.camelize
	 * Camelizes CSS names to work with JavaScript.
	 * @method string Slider.camelize(string name);
	 * @param string name
	 * @return string
	 * @example Slider.camelize('padding-left');
	 * @author Scott Doxey
	 */
	
	camelize: function(name) {
		return name.replace(/-([a-z])/g, function(str) { return String(str.match(/[a-z]/)).toUpperCase(); });
	},
	
	/**
	 * Slider.getStyle
	 * Retrieves any style (utilizing Slider.camelize) of a specified object.
	 * @method string Slider.getStyle(object object, string name);
	 * @param object object
	 * @param string name
	 * @return string
	 * @example Slider.getStyle(div, 'padding-left');
	 * @author Scott Doxey
	 */
	
	getStyle: function(object, name) {
		if (object.currentStyle) { var output = object.currentStyle[this.camelize(name)]; }
		else if (object.style && object.style[this.camelize(name)]) { var output = object.style[this.camelize(name)]; }
		else if (window.getComputedStyle) { var output = document.defaultView.getComputedStyle(object, null).getPropertyValue(name); }
		if (String(output).match(/^[0-9]+px$/)) { return Number(String(output).match(/[0-9]+/)[0]); } else { return 0; }
	}
	
};

Object.prototype.clone = function () {
	function Func() {}
	Func.prototype = this;
	return new Func();
};