jQuery.fn.infiniteCarousel = function ( $arrows, Args ) {

	function repeat(str, num) {
		return new Array( num + 1 ).join( str );
	}

	return this.each(function () {
		if ( Args == undefined )
		{
			Args = {
				itemWidth: undefined,
				itemHeight: undefined,
				visibleWidth: undefined,
				setStyle: undefined
			};
		}
		if (Args.itemWidth == undefined)
		{
			Args.itemWidth = jQuery('img', this).attr('width') > 0 ? jQuery('img', this).attr('width') : 105;
		}
		if (Args.itemHeight == undefined)
		{
			Args.itemHeight = jQuery('img', this).attr('height') > 0 ? jQuery('img', this).attr('height') : 80;
		}
		if (Args.visibleWidth == undefined)
		{
			Args.visibleWidth = 210;
		}
		if (Args.setStyle == undefined)
		{
			Args.setStyle = false;
		}

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

		if ( Args.setStyle )
		{
			jQuery(this).css({height: Args.itemHeight + 'px', overflow: 'hidden', position: 'relative'});
			$wrapper.css({position: 'absolute'});
			$slider.css({margin: 0, padding: 0, 'list-style': 'none'});
			$items.css({'display':'block', 'float':'left', 'width': Args.itemWidth + 'px', 'height': Args.itemHeight + 'px'});
		}

		var singleWidth = $single.outerWidth() == 0 ? Args.itemWidth : $single.outerWidth(),
			visible = Math.ceil( ( $wrapper.innerWidth() == 0 ? Args.visibleWidth : $wrapper.innerWidth() ) / singleWidth), // note: doesn't include padding or border
			currentPage = 1,
			pages = Math.ceil($items.length / visible);

			$slider.width( (2 + pages) * singleWidth * visible );

		// 1. Pad so that 'visible' number will always be seen, otherwise create empty items
		if (($items.length % visible) != 0) {
			$slider.append(repeat('<li class="empty">&nbsp;</li>', visible - ($items.length % visible)));
			$items = $slider.find('> li');
		}

		// 2. Top and tail the list with 'visible' number of items, top has the last section, and tail has the first
		$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

		if ( Args.setStyle )
		{
			// rewrite css for cloned and empty items
			$items.css({'display':'block', 'float':'left', 'width': Args.itemWidth + 'px', 'height': Args.itemHeight + 'px'});

			if ($slider.width() > 0 && ($wrapper.css('width') == 'auto' || $slider.width() > $wrapper.css('width')))
			{
				$wrapper.css({'width': $items.length * singleWidth + 'px'});
			}
		}

		// 3. Set the left position to the first 'real' item
		$wrapper.css('left', -1 * 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({
				left : '+=' + left
			}, 500, function () {
				if (page == 0) {
					$wrapper.css('left', -1 * singleWidth * visible * pages);
					page = pages;
				} else if (page > pages) {
					$wrapper.css('left', -1 * singleWidth * visible);
					// reset back to start position
					page = 1;
				}

				currentPage = page;
			});

			return false;
		}

//		$wrapper.after('<a class="arrow back">&lt;</a><a class="arrow forward">&gt;</a>');

		// 5. Bind to the forward and back buttons

		if ($arrows == undefined)
		{
			jQuery('a.back', this).click(function () {
				return gotoPage(currentPage - 1);
			});

			jQuery('a.forward', this).click(function () {
				return gotoPage(currentPage + 1);
			});
		}
		else
		{
			jQuery('a.back', $arrows).click(function () {
				return gotoPage(currentPage - 1);
			});

			jQuery('a.forward', $arrows).click(function () {
				return gotoPage(currentPage + 1);
			});
		}


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

//$(document).ready(function () {
//	$('.infiniteCarousel').infiniteCarousel();
//});
//$(document).ready(function () {
//	$('.infiniteCarousel').infiniteCarousel( jQuery('#arrows-container-here-optional') );
//});
