/*
	3D Carousel
*/
(function($) {
		  
	function Carousel(instance, options) {
		
		// holds all the current settings of the instance
		this.settings = $.extend({}, $.fn.carousel.defaults, options);
		
		// reference to the jQuery carousel instance
		var carousel = $(instance),
		
			// reference to the current object
			self = this,
			
			// index of the selected item
			selectedIndex = 0,
			
			// array of objects, each object containing all the data(path, link, tooltip etc.) for the respective carousel item
			items = [],
			
			// array of jQuery objects, each object corresponding to an item in the carousel
			divItems = [],
			
			// reference to PI
			PI = Math.PI,
			
			// used for transforming degrees to radians
			radians = PI / 180,
			
			// reference to the timer used when scrolling to a specific item (scrollToIndex(), scrollToNext() etc.)
			scrollTimer,
			
			// reference to the timer used for auto scrolling
			autoScrollTimer,
			
			// reference to the timer used for continuous scrolling
			continuousScrollTimer,
			
			// reference to the timer used for mouse scrolling
			mouseScrollTimer,
			
			// reference to the timer used for mouse drag scrolling
			mouseDragTimer,
			
			// reference to the timer used for mouse wheel scrolling
			mouseWheelTimer,
			
			// reference to the timer used for scrollbar scrolling
			scrollbarTimer,
			
			// indicates the current speed for the mouse scroll. the speed might be lower when the mouse is over the items
			currentMouseScrollSpeed = self.settings.mouseScrollSpeed,
			
			// holds the current X position of the mouse pointer
			mouseX,
			
			// holds the current Y position of the mouse pointer
			mouseY,
			
			// used for mouse drag scrolling to calculate the amount by which the carousel needs to rotate
			newMousePosition = 0,
			
			// used for mouse drag scrolling to calculate the amount by which the carousel needs to rotate
			oldMousePosition = 0,
			
			// indicates whether the carousel is currently scrolled using the mouse drag method
			isMouseDragging = false,
			
			// indicates whether the carousel is currently scrolled using the mouse wheel method
			isMouseWheelScrolling = false,
			
			// indicates whether the carousel is currently scrolled using the scrollbar
			isScrollbarDragging = false,
			
			// indicates whether the scrollbar is currently moving
			isScrollbarMoving = false,
			
			// a number from 0 to 1 that indicates the position of the thumb on the track
			scrollbarPosition = 0,
			
			// a number from 0 to 1 that indicates the rotation of the carousel. 1 indicates that the carousel is rotated by 360 degrees
			carouselRotation = 0,
			
			// X value for the center of the carousel
			centerX = self.settings.width / 2,
			
			// Y value for the center of the carousel
			centerY = self.settings.height / 2,
			
			// the top position of the actual carousel
			carouselTop = centerY - self.settings.verticalRadius,
			
			// the bottom position of the actual carousel
			carouselBottom = centerY + self.settings.verticalRadius,
			
			// the value of the angle between two consecutive items
			anglePerItem,
			
			// the total number of items in the carousel
			totalItems,
			
			// indicates whether the carousel is currently scrolling
			scrolling = false,
			
			// indicates whether the tooltip is currently displayed
			isTooltip = false,
			
			//IDs for elements on carousel
			IDs = new Array("clients", "case_studies", "work", "people", "contact")
			
		
		// START
		init();
		
		
		/**
		* Initializes the carousel
		*/
		function init() {
			
			carousel.addClass('carousel')
			 		.css({width: self.settings.width, height: self.settings.height});
			
			// if an XML file was specified, parse it
			if (self.settings.xmlSource) {
				// delete the content of the selected div
				carousel.empty();
				
				// load the XML file
				$.ajax({type:'GET', url:self.settings.xmlSource, dataType: $.browser.msie ? 'text' : 'xml', success:function(data) {																													
					var xml;
					
					if ($.browser.msie) {
						xml = new ActiveXObject('Microsoft.XMLDOM');
						xml.async = false;
						xml.loadXML(data);
					} else {
						xml = data;
					}
					
					// find all the <item> nodes
					$(xml).find('item').each(function() {
						// will contain data such as path, tooltip or link
						var carouselItem = {};
						
						// reads all the tags that were specified for an item in the XML file
						for (var i = 0; i < $(this).children().length; i++) {						
							var node = $(this).children()[i];
							carouselItem[node.nodeName] = $(this).find(node.nodeName).text();
						}
						
						items.push(carouselItem);
					});
					
					// create the carousel
					createCarousel();
				}});
			} else {
				// if an XML file was not specified, read the content of the selected div
				carousel.children().each(function() {					  
					// will contain data such as path, tooltip or link
					var carouselItem = {};
					
					// loops through all the sub-children of child
					for (var i = 0; i < $(this).children().length; i++) {
						var data = $(this).children()[i];
						
						// check whether the current sub-child is an image, a link, or a paragraph, and copy the data
						if($(data).is('a')) {
							carouselItem['path'] = $(data).find('img').attr('src');
							carouselItem['link'] = $(data).attr('href');
							if ($(data).attr('target'))
								carouselItem['linkTarget'] = $(data).attr('target');
						} else if($(data).is('img')) {
							carouselItem['path'] = $(data).attr('src');
						} else {
							carouselItem[$(data).attr('class')] = $(data).html();
						}
					}
					
					items.push(carouselItem);
				});
				
				// delete the current content of the selected div and create the carousel
				carousel.empty();					
				createCarousel();
			}
		}
		
		
		/**
		* Creates the carousel
		*/
		function createCarousel() {
			totalItems = items.length;				
			anglePerItem = (PI * 2) / totalItems;
			
			// create the carousel items
			for (var i = 0; i < totalItems; i++) {
				createCarouselItem(i);				
			}
			
			// arrange the items in a 3D perspective
			updatePosition(carouselRotation);
			
			// if the browser is not IE load the items in sequence, and start by loading the first item
			// loading the items in sequence in IE will throw a Stack Overflow error if there are more items
			if (!$.browser.msie)
				loadCarouselItem(0);
			
			// keep track of the current pointer position
			$(document).bind('mousemove',function(event) {
				mouseX = event.pageX;
				mouseY = event.pageY;
			});
			
			// disable the selecting behaviour in IE
			instance.onselectstart = function(){return false;}
			
			
			if (self.settings.autoScroll)
				startAutoScroll();
				
			if (self.settings.continuousScroll)
				startContinuousScroll();
				
			if (self.settings.mouseScroll)
				startMouseScroll();
				
			if (self.settings.mouseDrag)
				startMouseDrag();
				
			if (self.settings.mouseWheel)
				startMouseWheel();
				
			if (self.settings.scrollbar)
				createScrollbar();
			
			// create the tooltip and make it invisible
			if (self.settings.tooltip)
				$('<div class="tooltip"><p></p></div>').css('opacity', 0).appendTo(carousel);
		}
		
		
		/**
		* Creates a carousel item
		* Does not load the item yet
		*/
		function createCarouselItem(index) {
			
			var	carouselItem = $('<img class="carousel-item" id="' + IDs[index] + '"/>').appendTo(carousel);
			divItems.push(carouselItem);
			
			carouselItem.css({'width':self.settings.itemWidth, 'h':self.settings.itemHeight})
						.data({'w':self.settings.itemWidth, 'h':self.settings.itemHeight, 'index':index})
						.addClass('out')
						.bind({		   
							mouseover: function() {
								if ($(this).hasClass('out'))
									$(this).removeClass('out').addClass('over');
								
								// show tooltip
								if (self.settings.tooltip)
									showTooltip(index);
								
								// if mouse scroll is enabled, change its speed to a lower value
								if (self.settings.mouseScroll)
									currentMouseScrollSpeed = self.settings.mouseScrollSpeedHover;
								
								// fire the 'itemMouseOver' event
								var eventObject = {type:'itemMouseOver', index:index, data:items[index]};
								$.isFunction(self.settings.itemMouseOver) && self.settings.itemMouseOver.call(this, eventObject);
							},
							
							mouseout: function() {
								if ($(this).hasClass('over'))
									$(this).removeClass('over').addClass('out');
								
								// hide tooltip
								if (self.settings.tooltip)
									hideTooltip();
								
								// if mouse scroll is enabled, change its speed back to the normal value
								if (self.settings.mouseScroll)
									currentMouseScrollSpeed = self.settings.mouseScrollSpeed;
								
								// fire the 'itemMouseOut' event
								var eventObject = {type:'itemMouseOut', index:index, data:items[index]};
								$.isFunction(self.settings.itemMouseOut) && self.settings.itemMouseOut.call(this, eventObject);
							},
							
							click: function() {
								carousel.find('.click').removeClass('click').addClass('out');
								$(this).removeClass('over').addClass('click');
								
								// scroll to the clicked item
								if (self.settings.scrollOnClick)
									scrollToItem(index);
								
								// if a link was specified, navigate to the URL
								if(items[index].link) {
									window.open(items[index].link, items[index].linkTarget || self.settings.linkTarget);
								}
								
								// fire the 'itemClick' event
								var eventObject = {type:'itemClick', index:index, data:items[index]};
								$.isFunction(self.settings.itemClick) && self.settings.itemClick.call(this, eventObject);
							}
						 });
			
			// if a link was specified, set the item's cursor property to pointer
			if (items[index].link)
				carouselItem.css('cursor', 'pointer');
			
			// if the current browser is IE, load the item
			if ($.browser.msie)
				loadCarouselItem(index);
		}
		
		
		/**
		* Loads the image of the item
		*/
		function loadCarouselItem(index) {
			var path = items[index].path,
				carouselItem = divItems[index];
						  
			$('<img/>').load(function() {
								// hold a reference to the real width and height of the item	  
								var w = parseInt($(this).attr('width')) || parseInt($(this).prop('width')),
									h = parseInt($(this).attr('height')) || parseInt($(this).prop('height'));
								
								// if the item is cropped, set the image only as a background
								if (self.settings.crop) {
									carouselItem.css('background-image','url(' + path + ')');
								} else {
									carouselItem.attr('src', path);
									carouselItem.css('background-image','none');
								}
								
								// resize the item
								if (self.settings.resize) {
									if (self.settings.maintainAspectRatio) {
										scaleX = self.settings.itemWidth / w;
										scaleY = self.settings.itemHeight / h;
										if (scaleX < scaleY) {
											w *= scaleX;
											h *= scaleX;
										} else {
											w *= scaleY;
											h *= scaleY;
										}
									} else {
										w = self.settings.itemWidth;
										h = self.settings.itemHeigh;
									}
								}
								
								// set the width and height of the item to the modified values
								// and keep a reference to these values
								carouselItem.css({'width':w, 'height':h});
								carouselItem.data({'w':w, 'h':h});
								
								updatePosition(carouselRotation)
								
								// if the browser is not IE, load the items in sequence, using recursion
								if (!$.browser.msie)
									if (index < totalItems - 1)
										loadCarouselItem(++index);
							})
				          .attr('src', path);
		}
		
		
		/**
		* Updates the position of all items based on the rotation value
		*/
		function updatePosition(rotation) {
			carousel.find('.carousel-item').each(function(index) {									
				var carouselItem = $(this),
					
					// get a reference to the unaltered width and height of the item
					itemWidth = carouselItem.data('w'),
					itemHeight = carouselItem.data('h'),
					
					// calculate the initial left and top position of the item
					initialLeft = Math.cos(-(anglePerItem * index) + ((PI + self.settings.angle) * 0.5) + rotation * radians) * self.settings.horizontalRadius + centerX - itemWidth * 0.5, //
					initialTop = Math.sin(-(anglePerItem * index) + (PI * 0.5) + rotation * radians) * self.settings.verticalRadius + centerY - itemHeight * 0.5,
					
					// calculate the scale of the item based on its vertical position
					scale = ((initialTop - (carouselTop - itemHeight * 0.5)) / (carouselBottom - carouselTop)) * (1 - self.settings.scaleRatio) + self.settings.scaleRatio,
					
					// calculate the left and top position based on the scale of the item
					currentLeft = initialLeft + itemWidth * (1 - scale) / 2,
					currentTop = initialTop + itemHeight * (1 - scale) / 2;
				
				// assign the calculated values to the item
				carouselItem.css({'width': itemWidth * scale, 'height': itemHeight * scale,
								  'left': currentLeft, 'top': currentTop,
								  'z-index': Math.floor(scale * 10 * totalItems)});					
			});
			
			// if the scrollbar is not currently being dragged, update it's position manually
			if (self.settings.scrollbar && !isScrollbarDragging) {
				updateScrollbarPosition(getCarouselPosition());	
			}
		}
		
		
		/**
		* Scrolls to the item at the specified index
		*/
		function scrollToItem(index) {
			selectedIndex = index;
			
			// calcualte the rotation value that corresponds to the item
			var targetRotation = (anglePerItem * (180 / PI) * index) % 360;
			
			// "reset" the rotation
			carouselRotation %= 360;
			
			// calculate whether the carousel will rotate to the left or to the right
			if (Math.abs(targetRotation - carouselRotation) > 180)
				targetRotation += (targetRotation > carouselRotation) ? -360 : 360;

			if (targetRotation - carouselRotation > 180 && targetRotation > carouselRotation)
				targetRotation -= 360;			
			
			onScrollStart();
			
			// start rotating
			scrollTimer = setInterval(function() {					
				if (Math.abs(targetRotation - carouselRotation) > 0.5) {
					var increment = (targetRotation - carouselRotation) * (self.settings.scrollSpeed / 100);
					carouselRotation += increment;					
					updatePosition(carouselRotation);
				} else {
					onScrollComplete();
				}
			}, 30);
			
			// fire the 'itemSelect' event
			var eventObject = {type:'itemSelect', index:selectedIndex, data:items[selectedIndex]};
			$.isFunction(self.settings.itemSelect) && self.settings.itemSelect.call(this, eventObject);
		}
		
		
		/**
		* Scrolls to the next item
		*/
		function scrollToNext() {			
			var index = (selectedIndex == items.length - 1) ? 0 : (selectedIndex + 1);
			scrollToItem(index);
		}
		
		
		/**
		* Scrolls to the previous item
		*/
		function scrollToPrevious() {
			var index = selectedIndex == 0 ? (items.length - 1) : (selectedIndex - 1);
			scrollToItem(index);
		}
		
		
		/**
		* Starts the auto scrolling
		*/
		function startContinuousScroll() {
			self.settings.continuousScroll = true;
			
			onScrollStart();
			
			continuousScrollTimer = setInterval(function() {
				carouselRotation += 1;					
				updatePosition(carouselRotation);
			}, self.settings.continuousScrollSpeed);
		}
		
		
		/**
		* Stops the auto scrolling
		*/
		function stopContinuousScroll() {			
			self.settings.continuousScroll = false;
			clearTimeout(continuousScrollTimer);
		}
		
		
		/**
		* Starts the auto scrolling
		*/
		function startAutoScroll() {
			if (isTooltip && self.settings.pauseAutoScrollIfTooltip)
				return;
				
			self.settings.autoScroll = true;
			
			autoScrollTimer = setTimeout(function() {
				if (self.settings.autoScrollDirection == 'next')
					scrollToNext();
				else if (self.settings.autoScrollDirection == 'previous')
					scrollToPrevious();
			}, self.settings.autoScrollDelay);
		}
		
		
		/**
		* Stops the auto scrolling
		*/
		function stopAutoScroll() {			
			self.settings.autoScroll = false;
			clearTimeout(autoScrollTimer);
		}
		
		
		/**
		* Enables the mouse scrolling
		*/
		function startMouseScroll() {
			self.settings.mouseScroll = true;
			currentMouseScrollSpeed = self.settings.mouseScrollSpeed;
			
			var increment = 0,
				directionSign = self.settings.mouseScrollReverse ? -1 : 1;
			
			// start rotating
			mouseScrollTimer = setInterval(function() {
				// rotate only if the mouse pointer is over the carousel area
				if (mouseX > carousel.offset().left && mouseX < (carousel.offset().left + self.settings.width) && mouseY > carousel.offset().top && mouseY < (carousel.offset().top + self.settings.height)) {
					// calcualte the value by which the carousel is rotating based on the pointer's distance from the center of the carousel
					increment = directionSign * (mouseX - (carousel.offset().left + centerX)) * (currentMouseScrollSpeed / 1000);
					carouselRotation += increment;
					updatePosition(carouselRotation);
				} else {							
					if (Math.abs(increment) > 0.1) {
						// ease out the rotation
						increment *= (self.settings.mouseScrollEase/100);
						carouselRotation += increment;
						updatePosition(carouselRotation);
					} else {
						increment = 0;
					}
				}
			}, 30);
			
		}
		
		
		/**
		* Disables the mouse scrolling
		*/
		function stopMouseScroll() {
			self.settings.mouseScroll = false;
			clearInterval(mouseScrollTimer);
		}
		
		
		/**
		* Enables the mouse drag scrolling
		*/
		function startMouseDrag() {
			self.settings.mouseDrag = true;
			
			var rotationOnMouseDown = 0,
				directionSign = self.settings.mouseDragReverse ? 1 : -1;
				
			// when the user clicks on the carousel area start registering the mouse movement
			$(document).bind('mousedown', function(event) {
				if (mouseX > carousel.offset().left && mouseX < (carousel.offset().left + self.settings.width) && mouseY > carousel.offset().top && mouseY < (carousel.offset().top + self.settings.height)) {
						newMousePosition = oldMousePosition = event.pageX;
						rotationOnMouseDown = carouselRotation;
						$(document).bind('mousemove', mouseMoveHandler);
				}
			});
			
			// unregister the mouse movement
			$(document).bind('mouseup', function(event) {
				$(document).unbind('mousemove', mouseMoveHandler);
			});
			
			// keep track of the mouse position and if the carousel is not already rotation, start the rotation
			function mouseMoveHandler(event) {
				newMousePosition = event.pageX;
				if (!isMouseDragging) {
					onScrollStart();
					move();
				}
			}
			
			// rotate the carousel
			function move() {
				isMouseDragging = true;
				mouseDragTimer = setInterval(function() {
					// calcualte the amount of rotation based on the pointer's current position and the initial position
					var amount = directionSign * (newMousePosition - oldMousePosition) / (100 * self.settings.mouseDragSpeed),
						target = 360 * amount + rotationOnMouseDown,
						
						// calcualte the value by which the roation needs to be increased
						increment = (target - carouselRotation) * (self.settings.mouseDragEase / 100),
						absIncrement = increment >= 0 ? increment : -increment;
						
					if (absIncrement > 0.1) {
						carouselRotation += increment;
						selectedIndex = Math.round((carouselRotation * radians) / anglePerItem);
						updatePosition(carouselRotation);
					} else {
						onScrollComplete();
					}
				}, 30);
			}
			
		}
		
		
		/**
		* Disables the mouse drag scrolling
		*/
		function stopMouseDrag() {
			self.settings.mouseDrag = false;
			isMouseDragging = false;
			clearInterval(mouseDragTimer);
		}
		
		
		/**
		* Enables the mouse wheel scrolling
		*/
		function startMouseWheel() {
			self.settings.mouseWheel = true;
			
			var targetRotation = 0,
				directionSign = self.settings.mouseWheelReverse ? -1 : 1;
				
			// rotate the carousel on mousewheel event
			// this functionality requires a third party plugin
			carousel.bind('mousewheel', function(event, delta) {
				// disable page scrolling
				event.preventDefault();
				
				// if the mouse wheel scrolling is not already started, start it
				if (!isMouseWheelScrolling) {
					onScrollStart();
					isMouseWheelScrolling = true;
					targetRotation = carouselRotation;
					mouseWheelTimer = setInterval(function() {					
						if (Math.abs(targetRotation - carouselRotation) > 0.5) {
							// calcualte the value by which the roation needs to be increased
							var increment = (targetRotation - carouselRotation) * (self.settings.mouseWheelSpeed / 100);
							carouselRotation += increment;	
							selectedIndex = Math.round((carouselRotation * radians) / anglePerItem);
							updatePosition(carouselRotation);
						} else {
							onScrollComplete();
						}
					}, 30);
				}
				
				// update the target rotation based on the input from the mouse wheel
				targetRotation += directionSign * delta * 10;
			});
		}
		
		
		/**
		* Disables the mouse wheel scrolling
		*/
		function stopMouseWheel() {
			self.settings.mouseWheel = false;
			isMouseWheelScrolling = false;
			clearInterval(mouseWheelTimer);
		}
		
		
		/**
		* Creates the scrollbar
		*/
		function createScrollbar() {
			// add the scrollbar to the carousel area
			var scrollbar = $('<div class="scrollbar"></div>').appendTo(carousel),
				track = $('<div class="track"></div>').appendTo(scrollbar),
				thumb = $('<div class="thumb"></div>').appendTo(track),
				left = $('<div class="left"></div>').appendTo(scrollbar),
				right = $('<div class="right"></div>').appendTo(scrollbar),
				thumbPosition = 0,
				thumbOffset;
			
			// position the scrollbar
			scrollbar.css({'top':carouselBottom, 'left':centerX - parseInt(scrollbar.css('width')) / 2});
			
			
			// when the thumb is pressed, start registering its movement	
			thumb.bind('mousedown', function(event) {
				event.preventDefault();
				thumbOffset = mouseX - thumb.offset().left;				
				isScrollbarDragging = true;
				$(document).bind('mousemove', mouseMoveHandler);
			});
			
			// stop registering the movement when the mouse is released
			$(document).bind('mouseup', function() {
				if (isScrollbarDragging) {
					isScrollbarDragging = false;
					$(document).unbind('mousemove', mouseMoveHandler);
				}
			});
			
			
			// move the thumb
			function mouseMoveHandler() {
				thumbPosition = mouseX - track.offset().left - thumbOffset;				
				move();
			}
			
			// move the thumb on left arrow click
			left.bind('click', function() {
				thumbPosition = parseInt(thumb.css('left')) - self.settings.arrowScrollAmount;
				move();
			});
			
			// move the thumb or right arrow click
			right.bind('click', function() {
				thumbPosition = parseInt(thumb.css('left')) + self.settings.arrowScrollAmount;
				move();
			});
			
			
			function move() {
				// keep the thumb within bounderies
				if (thumbPosition < 0)
					thumbPosition = 0;
				else if (thumbPosition > parseInt(track.css('width')) - parseInt(thumb.css('width')))
					thumbPosition =  parseInt(track.css('width')) - parseInt(thumb.css('width'));
				
				// move the thumb
				if (isScrollbarDragging)
					thumb.css('left', thumbPosition);
				
				// calcualte the scrollbar position (a number between 0 and 1)
				scrollbarPosition = thumbPosition / (parseInt(track.css('width')) - parseInt(thumb.css('width')));
				
				// update the position of the carosel based on the thumb's position
				if (!isScrollbarMoving) {
					onScrollStart();
					isScrollbarMoving = true;
					// reset rotation
					carouselRotation %= 360;
					scrollbarTimer = setInterval(function() {							
						if (Math.abs(getCarouselPosition() - scrollbarPosition) > 0.001) {
							var increment = (scrollbarPosition - getCarouselPosition()) * (self.settings.scrollbarEase / 100);
							carouselRotation += increment * 360;
							selectedIndex = Math.round((carouselRotation * radians) / anglePerItem);
							updatePosition(carouselRotation);
						} else if (isScrollbarMoving) {
							onScrollComplete();
						}
					}, 30);
				}
			}
			
		}
		
		/**
		* Sets the position of the thumb when it is not being dragged
		*/
		function updateScrollbarPosition(position) {
			var track = carousel.find('.scrollbar').find('.track');
			var thumb = track.find('.thumb');
			
			thumb.css('left', position * (parseInt(track.css('width')) - parseInt(thumb.css('width'))));
		}
		
		
		/**
		* Returns a number from 0 to 1 representing the current rotation of the carousel
		* 0 corresponds to a rotation of 0 degrees while 1 corresponds to a rotation of 360 degrees
		*/
		function getCarouselPosition() {
			var position = (carouselRotation % 360) / 360;
			
			if(position < 0)
				position += 1;
			
			return position;
		}
		
		
		/**
		* This is called before starting any type of scrolling
		*/
		function onScrollStart() {
			clearTimers();
			
			if (!scrolling) {
				scrolling = true;
				
				// fire the 'scrollStart' event
				$.isFunction(self.settings.scrollStart) && self.settings.scrollStart.call(this);
			}
		}
		
		
		/**
		* This is called after the scrolling is complete
		*/
		function onScrollComplete() {
			clearTimers();
			
			if (scrolling) {
				scrolling = false;
				
				// fire the 'scrollComplete' event
				$.isFunction(self.settings.scrollComplete) && self.settings.scrollComplete.call(this);
			}
			
			// restart the mouse scrolling
			if (self.settings.mouseScroll)
				startMouseScroll();
			
			// restart the auto scrolling
			if (self.settings.autoScroll)
				startAutoScroll();
				
			// restart the continuous scrolling
			//if (self.settings.continuousScroll)
			//	startContinuousScroll();
		}
		
		
		/**
		* Clears all the timers
		* This has to be done before any type of scrolling in order to prevent conflicts
		*/
		function clearTimers() {
			if (mouseScrollTimer) {
				clearInterval(mouseScrollTimer);
			}
			
			if (mouseDragTimer) {
				isMouseDragging = false;
				clearInterval(mouseDragTimer);
			}
			
			if (mouseWheelTimer) {
				isMouseWheelScrolling = false;
				clearInterval(mouseWheelTimer);
			}
			
			if (scrollbarTimer) {
				isScrollbarMoving = false;
				clearInterval(scrollbarTimer);	
			}
			
			if (scrollTimer)
				clearInterval(scrollTimer);
			
			if (autoScrollTimer)
				clearTimeout(autoScrollTimer);
				
			if (continuousScrollTimer)
				clearTimeout(continuousScrollTimer);
		}
		
		
		/**
		* Shows the tooltip
		*/
		function showTooltip(index) {
			var tooltipContent = items[index].tooltip;
			
			// check if the item has a tooltip specified for it
			if (!tooltipContent)
				return;
			
			isTooltip = true;
			
			var tooltip = carousel.find('.tooltip');
			
			// add the text
			tooltip.find('p').html(tooltipContent);
			
			// fade in
			tooltip.stop().animate({'opacity':1}, 300);
			
			// calculate the position based on the size of the tooltip
			var tooltipLeft = - tooltip.outerWidth() / 2,
				tooltipTop = 0 - tooltip.outerHeight() - parseInt(tooltip.css('marginBottom'));
			
			// assign the values at start
			tooltip.css({'left':mouseX - carousel.offset().left + tooltipLeft, 'top':mouseY - carousel.offset().top + tooltipTop});
			
			// update the position as the mouse moves
			$(document).bind('mousemove.tooltip', function() {
				tooltip.css({'left':mouseX - carousel.offset().left + tooltipLeft, 'top':mouseY - carousel.offset().top + tooltipTop});
			});
			
			//stop the auto scrolling while the tooltip is displayed
			if (autoScrollTimer && self.settings.pauseAutoScrollIfTooltip)
				clearTimeout(autoScrollTimer);
		}
		
		
		/**
		* Hides the tooltip
		*/
		function hideTooltip() {			
			if (isTooltip) {
				isTooltip = false;
				
				var tooltip = carousel.find('.tooltip');
				
				tooltip.stop().animate({'opacity':0}, 200, function() {
														   		$(document).unbind('mousemove.tooltip');
																// position the tooltip outside of any visible area
																tooltip.css('left', -9999);
															});
				
				// resume the auto scrolling, if the feature is enabled
				if (self.settings.autoScroll && self.settings.pauseAutoScrollIfTooltip)
					startAutoScroll();
			}
		}
		
		
		
		// PUBLIC METHODS
		
		this.startAutoScroll = startAutoScroll;
		
		this.stopAutoScroll = stopAutoScroll;
		
		this.startContinuousScroll = startContinuousScroll;
		
		this.stopContinuousScroll = stopContinuousScroll;
		
		this.startMouseScroll = startMouseScroll;
		
		this.stopMouseScroll = stopMouseScroll;
		
		this.startMouseDrag = startMouseDrag;
		
		this.stopMouseDrag = stopMouseDrag;
		
		this.startMouseWheel = startMouseWheel;
		
		this.stopMouseWheel = stopMouseWheel;
		
		this.scrollToItem = scrollToItem;
		
		this.scrollToNext = scrollToNext;
		
		this.scrollToPrevious = scrollToPrevious;
		
		this.isScrolling = function() {
			return scrolling;	
		};
		
	}
	
	
	$.fn.carousel = function(options) {
		var collection = [];
		
		for (var i = 0; i < this.length; i++) {
			if (!this[i].carousel) {
				this[i].carousel = new Carousel(this[i], options);
				collection.push(this[i].carousel);
			}
		}
		
		// if there are more carousel instances, return the array of carousels
		// it there is only one, return just the carousel instance
		return collection.length > 1 ? collection : collection[0];
	};
	
	
	// default settings
	$.fn.carousel.defaults =  {
		xmlSource:null,
		width:500,
		height:300,
		itemWidth:100,
		itemHeight:100,
		horizontalRadius:250,
		verticalRadius:100,
		resize:true,
		maintainAspectRatio:true,
		crop:false,
		scaleRatio:0.5,
		mouseScroll:false,
		scrollOnClick:true,
		mouseDrag:false,
		scrollbar:false,
		arrowScrollAmount:50,
		tooltip:true,
		mouseScrollEase:90,
		mouseDragEase:10,
		scrollbarEase:10,
		scrollSpeed:10,
		mouseDragSpeed:20,
		mouseScrollSpeed:10,
		mouseScrollSpeedHover:3,
		mouseWheel:false,
		mouseWheelSpeed:10,
		mouseScrollReverse:false,
		mouseDragReverse:false,
		mouseWheelReverse:false,
		autoScroll:false,
		autoScrollDirection:'next',
		autoScrollDelay:3000,
		pauseAutoScrollIfTooltip:true,
		continuousScrollSpeed: 10,
		continuousScroll:false,
		linkTarget:'_blank',
		itemSelect:null,
		itemClick:null,
		itemMouseOver:null,
		itemMouseOut:null,
		scrollStart:null,
		scrollComplete:null,
		//angle of the orbit
		angle:0
	};
	
})(jQuery);
