jQuery.fn.infiniteCarousel = function(isSlideshow,transitionSpeed,isPagination,isNotInfinite,isHover){
	return this.each(function(){
		//if is SlideShow is set, then it must be able to carousel
		if(isSlideshow == true){
			isNotInfinite = false;
		}

		var $wrapper = jQuery('> div.wrapper', this).css('overflow', 'hidden'),
			$slider = $wrapper.find('> ul'),
			$items = $slider.find('> li'),
			$single = $items.filter(':first'),

			singleWidth = $single.outerWidth(),
			visible = Math.ceil(($wrapper.innerWidth() - 50) / (singleWidth+1)), // 50 is twice our scroll arrow div width, so we only show viewable area
			currentPage = 1,
			pages = Math.ceil($items.length / visible);

		// 1. Pad out the items to create an even multiple of visible items
		if(($items.length % visible) != 0){
            var remainder = (visible - ($items.length % visible));
            for(var x=0;x<remainder;x++) {
                $slider.append('<li class="empty" />');
            }
			$items = $slider.find('> li');
		}

		// 2. Clone the last page to the head of the list and the first page to the end
        //    to allow for "seamless" scrolling on wraparound
		$items.filter(':first').before($items.slice(- visible).clone().addClass('cloned'));
		$items.filter(':last').after($items.slice(0, visible).clone().addClass('cloned'));
		$items = $slider.find('> li'); // reselect

		// 3. Set the left position to the first uncloned item
		$wrapper.scrollLeft(singleWidth * (visible));

		// 4. paging function
		function gotoPage(page){
			var dir = page < currentPage ? -1 : 1,
				n = Math.abs(currentPage - page),
				left = singleWidth * dir * visible * n;

			$wrapper.filter(':not(:animated)').animate({ scrollLeft : '+=' + left }, transitionSpeed,
			function(){
				if(isNotInfinite){

					var arrowBack = $wrapper.parent().find('div.carousel_back a'),
					    arrowForward = $wrapper.parent().find('div.carousel_forward a');

					//by default both arrows are highlighted
					arrowBack.removeClass('inactive');
					arrowBack.unbind().click(function(){
						return gotoPage(currentPage - 1);
					});

					arrowForward.removeClass('inactive');
					arrowForward.unbind().click(function(){
						return gotoPage(currentPage + 1);
					});

					//set conditions where arrows are removed, or styled differently (MATTC you can define your inactive styles here)
					if(page == 1){
						arrowBack.addClass('inactive');
						arrowBack.unbind('click').click(function(e){
							e.preventDefault();
						});
						arrowBack.unbind('hover');
					}else if(page == pages){
						arrowForward.addClass('inactive');
						arrowForward.unbind('click').click(function(e){
							e.preventDefault();
						});
						arrowForward.unbind('hover');
					}
				}else{
					if(page == 0){
						$wrapper.scrollLeft(singleWidth * visible * pages);
						page = pages;
					}else if (page > pages){
						$wrapper.scrollLeft(singleWidth * visible);

						// reset back to start position
						page = 1;
					}
				}

				currentPage = page;

				//check to see if pagination is turned on and we have at least 2 pages for pagination
				if(isPagination && pages>1){

					//set a variable in the scope of the current context, so that we can call use this everywhere within this context
					var $allPages = jQuery(this).parent().find('ul.pagination li');

					//remove all highlights from pagination
					$allPages.attr('class','');

					//highlight the current page in the pagination
					$allPages.eq(currentPage-1).attr('class','active');
				}
			});
			return false;
		}

		if(pages>1){
			$wrapper.before('<div class="carousel_back"><a href="#"> </a></div>')
                    .after('<div class="carousel_forward"><a href="#"> </a></div>');
		}

		// 5. Bind to the forward and back buttons
		var arrowForward = jQuery('div.carousel_forward a', this),
		    arrowBack = jQuery('div.carousel_back a', this);


		arrowForward.unbind().click(function(){
			return gotoPage(currentPage + 1);
		});

		arrowBack.unbind().click(function(){
			return gotoPage(currentPage - 1);
		});

		//initialize slideshow,pagination,notInfinite if it's set in the arguments
		if (isSlideshow){
		   var slideInterval = setInterval(function(){gotoPage(currentPage + 1)},5000);
		   jQuery(this).parent().unbind().bind('mousemove', function(){
				 clearInterval(slideInterval);
		   }).bind('mouseleave', function(){
				 slideInterval = setInterval(function(){gotoPage(currentPage + 1)},5000);
		   });
		}

		if(isPagination){
			var pageItems = '';

			//add pagination markup only if there is more than one page
			if(pages>1){
				pageItems += '<ul class="pagination">';
				for(var i = 0;i<pages;i++){
					if(i==0){
						pageItems += '<li class="active"><a href="#"></a></li>';
					}else{
						pageItems += '<li><a href="#"></a></li>';
					}
				}
				pageItems += '</ul>';
			}

			//add markup to the carousel
			$wrapper.after(pageItems);

			jQuery('ul.pagination li', this).click(function(e){
				e.preventDefault();
				gotoPage(jQuery(this).index() + 1);
			});

			//center pagination
			jQuery('ul.pagination', this).css({
				left: (jQuery('ul.pagination', this).parent().width() - jQuery('ul.pagination', this).width()) / 2 + 'px'
			});
		}

		if(isNotInfinite){
			$wrapper.parent().find('div.carousel_back a').addClass('inactive');
			$wrapper.parent().find('div.carousel_back a').unbind('click').click(function(e){
				e.preventDefault();
			});
		}

		// create a public interface to move to a specific page
		jQuery(this).unbind().bind('goto', function (event, page){
			gotoPage(page);
		});
	});
};

