/**
 * jQuery.slider
 * 
 * @author	-	Tim O'Dell
 * @version	-	0.5
 * 
 * @param - show				-	INT			-	number of items to show in the slider
 * @param - step				-	INT			-	number if items to slide by, will not accept a number
 * 													gereater than set in show
 * @param - highlightItem		-	BOOL		-	if true will add a class to the first element then move
 * 													the highlight
 * @param - autoScroll			-	BOOL		-	if true slider will auto scroll, this will also use continuous
 * @param - autoTimer			-	INT			-	time delay between slide actions
 * @param - continuous			-	BOOL		-	if true the slider will continually scroll to the left
 * @param - speed				-	INT			-	static speed for the animation, the same speed will be used if 
 * 													the step is 1 or 100
 * @param - itemSpeed			-	INT			-	speed relative to 1 item, this is the speed to more 1 item, if
 * 													the step is set to 5, the animation will take 5 times the value 
 * 													passed to itemSpeed
 * @param - relativeSpeed		-	INT			-	speed relative to 100px, this will cause an item that is 200px 
 * 													to take twice as long to complete as one with a width of 100px
 * @param - easing				-	STRING		-	sets jquery animation easing
 * @param - prevText			-	STRING		-	text of the previous item (scroll to the right) link
 * @param - nextText			-	STRING		-	text of the next item (scroll to the left) link
 * @param - html				-	STRING		-	string of html to construct controls (can also be passed as an array)
 * @param - addEvents			-	CALLBACK	-	called when the plugin completes
 * @param - highlightComplete	-	FUNCTION	-	callen when the highlight has moved, but before the animation
 * 													completes
 */


(function ($){

	$.fn.slider = function (options){
		var params = $.extend({},defaultParams,options);
		
		return $(this).each(function (){
			
			$.extend(this,params);
			
			var pluginTarget = this,
				items = $(this).children(),
				obj = $(this);
			
			if(typeof(params.html) === 'string'){
				$(this).append(params.html);	
			}else if($.isArray(params.html)){
				$(this).append(params.html.join(''));
			};
			
			var itemWidth = $(items[0]).outerWidth(true),
				itemMargin = $(items[0]).outerWidth(true) - $(items[0]).outerWidth(false),
				sliderWidth = itemWidth * items.length;
			
			var $slider = $(this).find('.jqSlider-slider'),
				$hider = $(this).find('.jqSlider-hider'),
				$next = $(this).find('.jqSlider-next'),
				$prev = $(this).find('.jqSlider-prev');
			
			if(params.highlightItem !== false){
				var $itemNext = $('<div class="jqSlider-nextItem">Next Item</div>'),
					$itemPrev = $('<div class="jqSlider-prevItem">Previous Item</div>');
					
				$itemNext
					.click(function (){
						$('.jQSlider-highlight').each(function (){
							$(this)
								.removeClass('jQSlider-highlight')
								.next()
									.addClass('jQSlider-highlight')
							;
							if((($(this).prevAll().length + 1) / params.show) === 1){
								$next.click();
							};
							if($.isFunction(params.highlightComplete)){
								params.highlightComplete.call($(this).next());
							};
						});
					})
					.insertAfter($next)
				;
				$itemPrev
					.click(function (){
						$('.jQSlider-highlight').each(function (){
							$(this).removeClass('jQSlider-highlight');
							if($(this).prevAll().length === 0){
								$(this).parent().children().last().addClass('jQSlider-highlight');
								$prev.click();
							}else{
								$(this)
								.prev()
								.addClass('jQSlider-highlight')
							};
							if($.isFunction(params.highlightComplete)){
								params.highlightComplete.call($(this).prev());
							};
						});
					})
					.insertBefore($prev)
				;
				
			};
			
			if(params.step > params.show || typeof(params.step) === 'undefined'){	//	stops the step from being larger than the number of items shown
				params.step = params.show;
			};/* */
			if(params.step > items.length - params.show){ //	stops blank space from being shown
				params.step = items.length - params.show;
			};/* */
			
			if(params.show > items.length){
				var totalLength = itemWidth * items.length;
			}else{
				var totalLength = itemWidth * params.show;
			};
			
			$slider
				.append(items)
				.css({
					'width'		:	sliderWidth + 'px',
					'position'	:	'relative',
					'left'		:	'0px'
				})
			;/* $slider */

			$hider
				.css({
					'width'		:	(totalLength - itemMargin) + 'px',
					'overflow'	:	'hidden',
					'position'	:	'relative'
				})
			;/* $hider */
			
			var aniSpeed = function(){
				if(params.relativeSpeed){
					return ((itemWidth / 100) * params.relativeSpeed * params.step);
				}else if(params.itemSpeed){
					return params.itemSpeed * params.step;
				}else{
					return params.speed;
				};
			};/* aniSpeed */
			
			$next
				.html(params.nextText)
				.click(function (){
					var obj = this;
					if(!$($slider).is(':animated')){
						if(($hider.width() + itemMargin) - parseInt($slider.css('left').replace('px','')) < $slider.width()){
							$.event.trigger({'type' : 'jqSlider-moving-next','obj' : pluginTarget});
							var	distance = itemWidth * params.step,
								moveSpeed = aniSpeed();
							if(params.continuous === false){ // stops the slider moving past the end, showing blank space
								var distanceLeft = (($slider.width() - $hider.width()) + parseInt($slider.css('left').replace('px','')) - itemMargin);
								if(distanceLeft < distance){
									moveSpeed = (moveSpeed * (distanceLeft / distance));
									distance = distanceLeft;
								};
							};
							$slider
								.animate({
									left	:	'-=' + distance
								},
								moveSpeed,
								params.easing,
								function (){
									$.event.trigger({'type' : 'jqSlider-moved-next','obj' : pluginTarget});
									$.event.trigger({'type' : 'jqSlider-move-complete','obj' : pluginTarget});
									//	move elements around
									if(params.continuous === true){
										for (i = 1; i <= params.step; i++) {
											$slider.children().first().insertAfter($slider.children().last());
										};
										$slider.css('left','0px');
									};
									
								})
							;/* $slider */
						};
					};
				})/* .click() */
			;/* $next */
			$prev
				.html(params.prevText)
				.click(function (){
					if(!$($slider).is(':animated')){
						if(parseInt($slider.css('left').replace('px','')) < 0 || params.continuous === true){
							//	move elements around
							if(params.continuous === true){
								for (i = 1; i <= params.step; i++) {
									$slider.children().last().insertBefore($slider.children().first());
								};
								$slider.css('left','-' + (itemWidth * params.step) + 'px');
							};
							$.event.trigger({'type' : 'jqSlider-moving-previous','obj' : pluginTarget});
							var	distance = itemWidth * params.step,
								moveSpeed = aniSpeed();
								
							
							if(params.continuous === false){ // stops the slider moving past the end, showing blank space
								if(parseInt($slider.css('left').replace('px','')) + distance > 0){
									var overBy = parseInt(($slider.css('left').replace('px',''))) + distance;
									moveSpeed = moveSpeed * ((distance - (parseInt(($slider.css('left').replace('px',''))) + distance)) / distance);
									distance = distance - (parseInt($slider.css('left').replace('px','')) + distance);
								};
							};
							$slider
								.animate({
									left	:	'+=' + distance
								},
								moveSpeed,
								params.easing,
								function (){
									$.event.trigger({'type' : 'jqSlider-moved-previous','obj' : pluginTarget});
									$.event.trigger({'type' : 'jqSlider-move-complete','obj' : pluginTarget});
								})
							;/* $slider */
							
						};
					};
				})/* .click */
			;/* $prev */
			
			//	fires slider "atEnd" and "atStart" events
			$slider.bind('jqSlider-move-complete',function (event){
				if(event.obj === pluginTarget){
					var offset = $slider.width() - $hider.width() - itemMargin;
					if(parseInt($slider.css('left').replace('px','')) === 0){
						$.event.trigger({'type' : 'jqSlider-at-start','obj' : pluginTarget});
					};
					if(parseInt($slider.css('left').replace('px','')) === parseInt( '-'  + ($slider.width() - $hider.width() - itemMargin))){
						$.event.trigger({'type' : 'jqSlider-at-end','obj' : pluginTarget});
					};
				};
			});
			
			//	add event listener if autoScroll is set to true
			if(params.autoScroll === true){
				params.autoScrollTarget = $next;
				if (params.continuous === false) {
					$slider
						.bind('jqSlider-at-end', function(event){
							if(event.obj === pluginTarget){
								params.autoScrollTarget = $prev;	
							};
						})
						.bind('jqSlider-at-start', function(event){
							if(event.obj === pluginTarget){
								params.autoScrollTarget = $next;
							};
						})
					;
				};
				var timer;
				var startTimer = function (){
					timer = setTimeout(function (){
						params.autoScrollTarget.click();
						startTimer();
					}, params.autoTimer);
				};
				$slider
					.add($next)
					.add($prev)
						.mouseenter(function (){
							clearTimeout(timer);
						})
						.mouseleave(function (){
							startTimer();
						})
				;/* */
				startTimer();
			};
			
			if(params.highlightItem === true){
				$slider.children().first().addClass('jQSlider-highlight');
				var timer;
				var startTimer = function (){
					timer = setTimeout(function (){
						$('.jQSlider-highlight').each(function (){
							$(this).removeClass('jQSlider-highlight').next().addClass('jQSlider-highlight');
							if((($(this).prevAll().length + 1) / params.show) === 1){
								$next.click();
							};
							if($.isFunction(params.highlightComplete)){
								params.highlightComplete.call($(this).next());
							};
						});
						startTimer();
					}, params.autoTimer);
				};
				$slider
					.add($itemPrev)
					.add($itemNext)
					.add($prev)
					.add($next)
						.mouseenter(function (){
							clearTimeout(timer);
						})
						.mouseleave(function (){
							startTimer();
						})
				;/* */
				startTimer();
			};
			
			if($.isFunction(params.addEvents)){
				params.addEvents.call(this)
			};
			
		});/* return $(this).each */
	};/* $.fn.slider */

	var defaultParams = {
		show			:	3,			//	number of items to show in the slider
		step			:	1,			//	number if items to slide by, will not accept a number gereater than set in show
		highlightItem	:	false,		//	if true will add a class to the first element then move the highlight
		autoScroll		:	false,		//	if true slider will auto scroll, this will also use continuous
		autoTimer		:	1000,		//	time delay between slide actions
		continuous		:	false,		//	if true the slider will continually scroll to the left
//		scrollDirection	:	'left',		//	NOT YET IMPLEMENTED accepts 'left' or 'right'
		speed			:	500,		//	static speed for the animation, the same speed will be used if the step is 1 or 100
		itemSpeed		:	false,		//	speed relative to the 1 item, this is the speed to more 1 item, if the step is set to 5, the animation will take 5 times the value passed to itemSpeed
		relativeSpeed	:	false,		//	speed relative to 100px, this will cause an item that is 200px to take twice as long to complete as one with a width of 100px
		easing			:	'linear',	//	sets jquery animation easing
		prevText		:	'Previous',	//	text of the previous item (scroll to the right) link
		nextText		:	'Next',		//	text of the next item (scroll to the left) link
		html			:	[			//	stucture of the html for the slider will accept a sting or an array ad below
								'<div class="jqSlider-prev"></div>',
								'<div class="jqSlider-hider">',
								'	<div class="jqSlider-slider clrNM">',
								'	</div>',
								'</div>',
								'<div class="jqSlider-next"></div>',
							].join('')
	};/* defaultParams */
	
})(jQuery)
