;(function($) {

	(function($,sr){
	 
	  // debouncing function from John Hann
	  // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
	  var debounce = function (func, threshold, execAsap) {
		  var timeout;
	 
		  return function debounced () {
			  var obj = this, args = arguments;
			  function delayed () {
				  if (!execAsap)
					  func.apply(obj, args);
				  timeout = null; 
			  };
	 
			  if (timeout)
				  clearTimeout(timeout);
			  else if (execAsap)
				  func.apply(obj, args);
	 
			  timeout = setTimeout(delayed, threshold || 100); 
		  };
	  }
		// smartresize 
		jQuery.fn[sr] = function(fn){  return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
	 
	})(jQuery,'smartresize');
 

    jQuery.fn.slideSelector = function(options, clickHandler) {
		
		var container = $(this);
		var viewWidth = container.width();
		var trayWidth = 0;
		var sliding = false;
		var currOffset = 0;
		var thumbTray = {};
		var allThumbs = {};
		var enabled = false;

		var settings = jQuery.extend({
			hitSpotSize : 100,
			velocity : 300 / 1000, //px / sec
			thumbSelector : ".thumb",
			traySelector : ".thumbs",
			buttons: { pre : $(), next: $() },
			mode: "hover"
		  }, options);


		function mouseMovement(eM) {

			if(!enabled) { return; }

			var mouseX = eM.pageX - currOffset;

			if(slideTriggerLeft(mouseX) && !sliding) {
				slideRight();
			}
			else if(slideTriggerRight(mouseX) && !sliding) {
				slideLeft();
			}
			else if(!slideTriggerRight(mouseX) && !slideTriggerLeft(mouseX) && sliding) {
				stopSliding();
			}
			//Ignores if not in trigger area and not sliding 
			//OR already sliding inside trigger area	
		};

		function stopSliding() {
			sliding = false;
			$(thumbTray).stop();
			$(thumbTray).queue("fx", []);
		}

		function slideLeft(distance, time) {

			if(!enabled) { return; }
			sliding = true;

			var trayX = $(thumbTray).position().left;

			var distToGo = trayWidth - viewWidth - Math.abs(trayX);
			distToGo = Math.abs(distance == null ? distToGo : distance); //get absolute value

			var moveAmount = "-="+distToGo+"px";

			var timeout = time != null ? time : 1/(settings.velocity / distToGo);

			$(thumbTray).animate({"left":moveAmount}, timeout);

		}
		//Checks left pos, brings it back to 0
		function slideRight(distance, time) {

			if(!enabled) { return; }
			sliding = true;

			var trayX = $(thumbTray).position().left;
			var distToGo = Math.abs(distance == null ? trayX : distance);

			var moveAmount = "+="+distToGo+"px";

			var timeout = time != null ? time : 1/(settings.velocity / distToGo);

			$(thumbTray).animate({"left":moveAmount}, timeout);
		}

		function slideTriggerLeft(pos) {
			return (pos > 0 && pos < settings.hitSpotSize)
		}
		function slideTriggerRight(pos) {
			return (pos > viewWidth - settings.hitSpotSize && pos < viewWidth)
		}

		function jumpPre() {

			stopSliding();

			var distanceToMove = (function() {

				var thumbs = allThumbs.get();

				for(var i = thumbs.length - 1; i >= 0; i--) {
					var thumbX = $(thumbs[i]).offset().left - currOffset;
					var thumbW = $(thumbs[i]).outerWidth();

					if(thumbX < 0) {
						// Calc distance to stick the next image in the center
						if(i != 0) {
							var distance = (viewWidth/2) - (viewWidth - thumbX) + (thumbW/2);
							settings.buttons.next.removeClass("disabled");
						}
						else {
							var distance = thumbX;
							settings.buttons.pre.addClass("disabled");
						}
						return distance;
					}
				}
				return 0;
			})();
			
			slideRight(distanceToMove);
		}

		function jumpNext() {

			stopSliding();

			var distanceToMove = (function() {

				var thumbs = allThumbs.get();

				for(var i in thumbs) {
					var thumbX = $(thumbs[i]).offset().left - currOffset;
					var thumbW = $(thumbs[i]).outerWidth();

					if(thumbX + thumbW > viewWidth) {
						// Calc distance to stick the next image in the center
						if(i != thumbs.length - 1) {
							var distance = (viewWidth/2) - (viewWidth - thumbX) + (thumbW/2);
							settings.buttons.pre.removeClass("disabled");
						}
						else {
							var distance = thumbW - (viewWidth - thumbX); // last thumb, move to edge
							settings.buttons.next.addClass("disabled");
						}
						return distance; 
					}
				}
				return 0;
			})();
			
			slideLeft(distanceToMove);
		}

		function goToThumb(index, time) {

			stopSliding();

			var thumbs = allThumbs.get();
			var requestedThumb = allThumbs.get(index);
			var thumbX = $(requestedThumb).offset().left - currOffset;
			var thumbW = $(requestedThumb).outerWidth();

			var distanceToMove = (function() { 
				if(thumbX + thumbW > viewWidth) {
					return thumbW - (viewWidth - thumbX); // move to end edge
				}
				else if(thumbX < 0) {
					return thumbX;	// move to start edge
				}
				else {
					return 0;
				}
			})();

			if(distanceToMove < 0) {
				slideRight(distanceToMove, time);
			}
			else if(distanceToMove > 0) {
				slideLeft(distanceToMove, time);
			}

			$(container).find('.current').removeClass("current");
			$(requestedThumb).addClass("current");
		}

		function initialize() {

			//Get all the thumbnails
			allThumbs = container.find(settings.thumbSelector);

			//Figure out total width
			var widthBuffer = 0;

			allThumbs.each(function() {

				widthBuffer += $(this).outerWidth();

				if(clickHandler && typeof clickHandler == "function") { 
					$(this).click(function() {
						clickHandler.call($(this), $(allThumbs).index(this));
					});
				}	
				else {
					$(this).click(function() {
						goToThumb($(allThumbs).index(this));
					});
				}

			});
			
			//Set to new width (so it will flow thumbs horizontally)
			thumbTray = container.find(settings.traySelector);
			trayWidth = widthBuffer;	//cache tray width, for speedier look up
			thumbTray.width(trayWidth);

			if(trayWidth > viewWidth) {
				enabled = true;
				currOffset = container.offset().left;
			}
		
			// Setup events
			$(window).smartresize(function() {
				currOffset = container.offset() == null ? currOffset : container.offset().left;
			});

			if(settings.mode == "hover") {
				//Detect movement into slide triggers
				container.mousemove(mouseMovement);

				//Hovering over thumbs, turn on slider
				container.hover(function() {}, stopSliding);
			}
			else {
				// @NOTE: mousedown events experimental and too buggy right now

				//settings.buttons.pre.bind("mousedown", function() { slideRight(); });
				settings.buttons.pre.bind("click", jumpPre);

				//settings.buttons.next.bind("mousedown", function() { slideLeft(); });
				settings.buttons.next.bind("click", jumpNext);
			}
		};
		
		function resetAll() {
			goToThumb(0,0);		
			container.unbind("mousemove");	
			container.unbind("hover");	
			allThumbs.unbind("click");
			settings.buttons.pre.unbind("click");
			settings.buttons.next.unbind("click");
		};

		var public = {
			goto : goToThumb,
			next: jumpNext,
			prev: jumpPre,
			init : initialize,
			reset : resetAll
		};

		return public;

    }; // end plugin

})(jQuery);


