// jQuery Carousel with Scrollbar
// Plugin written by Radoslav Georgiev
// c4xpl0siv3@gmail.com

jQuery(function($) {
	var car;
	$.fn.scrollcarousel = function(options) { 
		var defaults = {  
			navigation :        	null,
			buttonPrev:           true,
			buttonNext:           true,
			start:                1,
			auto:                 0,
			displayIndex:         true,
			easing:               null,
			speed:                "slow",
			wrap: 	             "both",
			maxScroll:            0,
			autoAlign:            true,
			handleHTML:           "<span>&nbsp;</span>",
			scrollStrings:        null,
			scrollType:           "normal", // Couldbe normal or cool
			carouselLoadedCallback: null,
			carouselScrolledCallback: null,
			itemLoadCallback:      null,
			itemVisibleCallback:   null
		};  
		var options = $.extend(defaults, options);  
		
		var mouse = function(){
			this.left = 0;
			this.top = 0;
		}
			
		return this.each(function() {  
			car = this;
			var obj = $(this);
			var htmlObj = this;
			var carouselList =  $("ul:eq(0)", obj);
					
			var current = options.start-1;
			
			var element = new function(){
				this.width = $("li:eq(0)", carouselList).outerWidth();
				this.height = $("li:eq(0)", carouselList).outerHeight();
				this.count = carouselList.find("li").size();
			}		
			
			// Setting ul's width - all li's shoudle be in one row
			carouselList.css("width", element.width * element.count);
			carouselList.css("left" , -((options.start-1)*element.width));
			
			var scrollContainer = null;
			if(options.navigation == "scroll")
			{
				var newHTML = document.createElement("div");
				$(newHTML).attr("class", "carousel-scroll");
				obj.append(newHTML);
				scrollContainer = $(".carousel-scroll", obj);
			}
			var scrollHandle = null;
			var scrollRatio;
			var scrollSpacing;
			var setScrollData;
			
			if(scrollContainer)
			{
				var newHTML = document.createElement("div");
				$(newHTML).attr("class", "scrollcarousel-handle");
				scrollContainer.append(newHTML);
				scrollHandle = $(".scrollcarousel-handle" ,scrollContainer);
				scrollHandle.css("width", scrollContainer.width()/element.count);
				scrollSpacing = (scrollContainer.width() - scrollHandle.outerWidth()*(element.count))/(element.count -1);
				if(scrollHandle.outerWidth()==scrollContainer.width()/element.count) scrollSpacing = 0;
				scrollRatio = (scrollHandle.outerWidth() + scrollSpacing)/element.width;
				scrollHandle.css("left", current*scrollHandle.outerWidth() + current*scrollSpacing);
				scrollHandle.html(options.handleHTML);
			
				setScrollData = function(num){
					if(!options.displayIndex) return;
					
					if(options.scrollStrings)
					{
						if(options.scrollType == "normal")
						{
							if(options.scrollStrings[num-1])
								$("span", scrollHandle).html(options.scrollStrings[num-1]);
							else
								$("span", scrollHandle).html(num);
						}
					}
					else
						$("span", scrollHandle).html(num);
				}
				
				if(options.scrollType == "cool")
				{
					var list = document.createElement("ul");
					scrollContainer.append(list);
					scrollList = $("ul", scrollContainer);
					for(i=0; i<options.scrollStrings.length; i++)
					{
						var li = document.createElement("li");
						if(typeof(options.scrollStrings[i]) == "string")
						{
							var li = document.createElement("li");
							$(li).html(options.scrollStrings[i]);
							scrollList.append(li);
						}
						else
						{
							for(k=0; k<options.scrollStrings[i]; k++)
							{
								var li = document.createElement("li");
								$(li).html("&nbsp;");
								scrollList.append(li);								
							}
						}
					}
					$("li", scrollList).width(scrollHandle.outerWidth()+scrollSpacing);
				}
				
				 setScrollData(options.start);
			}
			var buttonNext = null;
			var buttonPrev = null;
			
			var navigationDiv, navigationList;
			var updateNavigationDot;
			
			if(options.navigation == "dots")
			{
				var div = document.createElement("div");
				$(div).attr("class", "slider-navigation");
				obj.append(div);
				navigationDiv = $(".slider-navigation", obj);
				
				navigationList = document.createElement("ul");
				navigationDiv.append(navigationList);
				navigationList = $(".slider-navigation ul", obj);
				
				for(var i=0; i<element.count; i++)
				{
					var lItem = document.createElement("li");
					var lLink = document.createElement("a");
					$(lLink).attr("href", "#");
					$(lLink).html(i+1);
					if(i==current) $(lLink).addClass("active");
					$(lItem).append(lLink);
					navigationList.append(lItem);
					
					var thisLink = $(".slider-navigation ul li a", obj).eq(i);
					thisLink.click(function(){
					scrollTo($(this).parent().index()+1);				
						$("a", navigationList).removeClass("active");
						$(this).addClass("active");
						return false;
					});
				}
				
				updateNavigationDot = function()
				{
					$("a", navigationList).removeClass("active");
					$("li", navigationList).eq(current-1).find("a").addClass("active");
				}
			}
			
			buttonClicked = false;
			
			if(options.buttonNext)
			{
				obj.append("<div class=\"scrollcarousel-next\">Next</div>");
				buttonNext = $(".scrollcarousel-next", obj);	
			}
			
			if(options.buttonPrev)
			{
				obj.append("<div class=\"scrollcarousel-prev\">Prev</div>");
				buttonPrev = $(".scrollcarousel-prev", obj);	
			}
			
			
			var buttonClicked = false;
			
			var scrollNextCount = 0;
			var carouselTimeout;
			
			function next(){
				if(!carouselList.is(":animated"))
				{
					clearTimeout(carouselTimeout);
					
					var currentX = carouselList.position().left;
					
					currentX = currentX - (currentX % element.width);
					var currEl = currentX / element.width;
					
					
					if(currentX != -(element.width*(element.count-1)))
					{	
						var nextX = (currEl-1)*element.width;
						if(false)
						carouselList.animate({ left: nextX}, options.speed, options.easing);
						else
						{
							carouselList.fadeOut("fast", function(){
								carouselList.css("left", nextX);
								carouselList.fadeIn();						
							});
						}
						if(scrollContainer)
						{
							scrollNextX = (-currEl+1)*(scrollHandle.outerWidth()+scrollSpacing);
							scrollHandle.animate({left: scrollNextX }, options.speed, options.easing);
							setScrollData(-currEl+2);
							if(options.itemLoadCallback)
								options.itemLoadCallback(htmlObj, -currEl+2, element.count, options);
							if(options.itemVisibleCallback)
								options.itemVisibleCallback(htmlObj,-currEl+2,  element.count, options);
								
						}
						current = -currEl + 2;
					}
					else if(options.wrap=="both" || options.wrap == "right")
					{
						if(false)
							carouselList.animate({left:0}, options.speed, options.easing);
						else
						{
							carouselList.fadeOut("fast", function()
							{
								carouselList.css("left", 0);
								carouselList.fadeIn();
							});
						}
						if(scrollContainer)
						{
							scrollHandle.animate({left:0}, options.speed, options.easing);
							setScrollData(1);
							if(options.itemLoadCallback)
								options.itemLoadCallback(htmlObj, 1, element.count, options);
							if(options.itemVisibleCallback)
								options.itemVisibleCallback(htmlObj, 1, element.count, options);
						}
						current = 1;
					}				
					
						buttonClicked = false;
					if(options.navigation == "dots") updateNavigationDot();
					
					scrollNextCount--;	
						
					if(options.auto)
					{
						carouselTimeout = setTimeout(next, options.auto * 1000);
					}				
				}
				else
				{
					//if(scrollNextCount) setTimeout(next ,0.5);
				}
			}
			
			this.next = next;
			
			if(options.auto)
			{
				carouselTimeout = setTimeout(next, options.auto * 1000);
			}
			
			if(options.buttonNext)
			{
				buttonNext.click(function(){
					buttonClicked = true;
					if(scrollNextCount<options.maxScroll) scrollNextCount++;
					next();
					return false;
				});
			}
			
			
			var scrollPrevCount = 0;
			
			function prev(){
				if(!carouselList.is(":animated"))
				{
					clearTimeout(carouselTimeout);
					
					var currentX = carouselList.position().left;
					currentX = currentX - (currentX % element.width);
					
					var currentX = carouselList.position().left;
					currentX = (!(currentX % element.width)) ? currentX: currentX - (currentX % element.width) - element.width;
					var currEl = currentX / element.width;
					
					if(currentX < 0)
					{	
						var nextX = (currEl+1)*element.width;
						if(false)
							carouselList.animate({ left: nextX }, options.speed, options.easing);
						else
						{
							carouselList.fadeOut("fast", function(){
								carouselList.css("left", nextX);
								carouselList.fadeIn();
							});
						}
						if(scrollContainer)
						{
							scrollNextX = (-currEl-1)*scrollHandle.outerWidth() + (-currEl-1)*scrollSpacing;
							scrollHandle.animate({left: scrollNextX}, options.speed, options.easing);
							setScrollData(-currEl);
							if(options.itemLoadCallback)
								options.itemLoadCallback(htmlObj, -currEl, element.count, options);
								
							if(options.itemVisibleCallback)
								options.itemVisibleCallback(htmlObj,-currEl, element.count, options);
						}
						current = -currEl; 
					}
					else if(options.wrap=="both" || options.wrap == "left")
					{
						if(false)
							carouselList.animate({left: -(carouselList.width()-element.width)}, options.speed, options.easing);
						else
						{
							carouselList.fadeOut("fast", function(){
								carouselList.css("left", -(carouselList.width()-element.width));
								carouselList.fadeIn();
							});	
						}
						
						
						if(scrollContainer)
						{
							nextScrollX = (element.count-1)*scrollHandle.outerWidth() + (element.count-1)*scrollSpacing;
							scrollHandle.animate({left: nextScrollX }, options.speed, options.easing);
							setScrollData(element.count);
							if(options.itemLoadCallback)
								options.itemLoadCallback(htmlObj, element.count, element.count, options);
							if(options.itemVisibleCallback)
								options.itemVisibleCallback(htmlObj,element.count,  element.count, options);
						}
						current = element.count;
					}			
					
					buttonClicked = false;	
					
					if(options.navigation == "dots") updateNavigationDot();
					
					scrollPrevCount--;	
					
					if(options.auto) carouselTimeout =  setTimeout(next, options.auto * 1000)				
					}
				else
				{
					//if(scrollPrevCount) setTimeout(prev ,0.5);
				}
			}
			
			this.prev = prev;
			
			if(options.buttonPrev)
			{
				buttonPrev.click(function(){
					buttonClicked = true;
					//if(scrollPrevCount<options.maxScroll) scrollPrevCount++;
					prev();
					return false;
				});
			}
			
			function scrollTo(smtg, settimeout)
			{
				settimeout = (typeof(settimeout)!='undefined') ? settimeout : true;
				if(smtg != null && (smtg<1 || smtg>element.count)) return;
				
				clearTimeout(carouselTimeout);
				
				var m_current;
				if(smtg)
				{
					m_current = smtg;
					if(options.navigation == "scroll") setScrollData(smtg);
					if(options.itemLoadCallback)
						options.itemLoadCallback(htmlObj, smtg, element.count, options);
					if(options.itemVisibleCallback)
						options.itemVisibleCallback(htmlObj,smtg, element.count, options);
				}
				else m_current = current;
				
				var nextX = -(m_current-1)*element.width;
				
				carouselList.fadeOut("fast", function(){
					carouselList.css("left", nextX);
					carouselList.fadeIn();
				});
				
				/* ------------------------------------------------------------------------------------------- */
				
				
				if(options.navigation == "scroll") 
					scrollHandle.animate({
						left: (m_current-1)*(scrollHandle.outerWidth() + scrollSpacing)
				}, options.speed, options.easing);
					
				if(options.navigation == "dots") updateNavigationDot();
				
				current = m_current;
				
				if(options.navigation == "dots") updateNavigationDot();
				
				
				if(options.auto && settimeout && !scrollFocused) carouselTimeout = setTimeout(next, options.auto * 1000);
			}
			this.goTo = scrollTo;
			
			function pause()
			{
				clearTimeout(carouselTimeout);	
			}
			this.pause = pause;
			
			function resume()
			{
				if(options.auto)
				carouselTimeout = setTimeout(next, options.auto * 1000);	
			}
			this.resume = resume;
			
			this.setAuto = function(interval)
			{
				options.auto = interval;
			}
			
			var scrollFocused;
			
			// Scroller Stuff
			if(options.navigation == "scroll")
			{
				
				var mouseMoveTimeOut, initLeft, initMouseLeft, scrollEnabled, mouseWasDown = false;
			
				var clickedButton;
				
				scrollContainer.click(function(){
					setTimeout(directClick, 1);							   
				});
				
				scrollContainer.mousewheel(function(event, delta) {
					var maxSteps = 1;
					if(Math.abs(delta)>maxSteps) delta = (delta>0) ? maxSteps : --maxSteps;
					current = (current+delta>0 && current+delta<=element.count) ? current + delta : 1;
					scrollTo(current, false);
				});
				
				scrollContainer.hover(function(){
					scrollFocused = true;
					pause();							   
				}, function(){
					scrollFocused = false;
					resume();	
				});
				
				function directClick()
				{
					if(!clickedButton)
					{
						if(carouselList.is(":animated")) return;
						clearTimeout(carouselTimeout);
						
						var left = mouse.left - scrollContainer.offset().left;
						var top = mouse.top - scrollContainer.offset().top;
						
						var stepW = scrollHandle.width() + scrollSpacing;
						for(i=0; i<element.count; i++)
						{
							if(left > i*stepW - scrollSpacing/2 && left < (i+1)*stepW - scrollSpacing/2  )
								scrollTo(i+1);
						}
						
						clickedButton = false;
					}
					else clickedButton = false;
				}
					
				function moveScroll()
				{
					if(!scrollEnabled) return;
					clearTimeout(carouselTimeout);
					
					var newPos = (mouse.left-initMouseLeft) + initLeft;
					if(newPos>=0 && newPos <= scrollContainer.width()-scrollHandle.outerWidth())
					{
						scrollHandle.css("left", newPos);
						carouselList.css("left", -newPos/scrollRatio);
						var temp = carouselList.width()+(-newPos/scrollRatio);
						temp = element.count - (temp-((temp-(element.width/2))%element.width))/element.width;
						var temp2 = temp - (temp%1) +1;
						current = temp2;
						if(scrollHandle.html()!=temp2) setScrollData(temp2);
						if(options.itemVisibleCallback)
								options.itemVisibleCallback(htmlObj,temp2, element.count, options);
					}
					else if(newPos<0)
					{
						scrollHandle.css("left", 0);
						carouselList.css("left", 0);
					}
					else if(newPos > scrollContainer.width()-scrollHandle.outerWidth())
					{
						scrollHandle.css("left", scrollContainer.width()-scrollHandle.outerWidth());
						carouselList.css("left", -(carouselList.width()-element.width))
					}
				}
				
				scrollHandle.mousedown(function(){
					initLeft = scrollHandle.position().left;
					initMouseLeft = mouse.left;
					scrollEnabled = true;
					clickedButton = true;
					clearTimeout(carouselTimeout)
					
					return false;
				});
				
				$(document).mouseup(function(){
					
					if(scrollEnabled)
					{
						scrollEnabled = false;
												
						if(options.auto)
						{
							//carouselTimeout = setTimeout(next, options.auto * 1000);
						}
						
						if(options.autoAlign)
						{
							scrollTo(current, false);	
						}
					}
					
				});
				
				
				$(document).mousemove(function getMouseXY(e) {
				  if (IE) { // grab the x-y pos.s if browser is IE
					mouse.left = event.clientX + document.body.scrollLeft;
					mouse.top = event.clientY + document.body.scrollTop;
				  } else {  // grab the x-y pos.s if browser is NS
					mouse.left = e.pageX;
					mouse.top = e.pageY;
				  }  
				  // catch possible negative values in NS4
				  if (mouse.left < 0){mouse.left = 0};
				  if (mouse.top < 0){mouse.top = 0};
				  // show the position values in the form named Show
				  // in the text fields named MouseX and MouseY
				  
				  moveScroll();
								  
				  
				  return true;
				});
			
				scrollHandle.disableSelection();
		
			}
			
			if(options.buttonPrev) buttonPrev.disableSelection();
			buttonNext.disableSelection();
			
			if(options.carouselLoadedCallback)
				options.carouselLoadedCallback(this, current, element.count, options);
			
		});  
	};
});

jQuery.fn.extend({ 
        disableSelection : function() { 
                return this.each(function() { 
                        this.onselectstart = function() { return false; }; 
                        this.unselectable = "on"; 
                        jQuery(this).css('user-select', 'none'); 
                        jQuery(this).css('-o-user-select', 'none'); 
                        jQuery(this).css('-moz-user-select', 'none'); 
                        jQuery(this).css('-khtml-user-select', 'none'); 
                        jQuery(this).css('-webkit-user-select', 'none'); 
                }); 
        } 
});
