/**
 * Infinite Carousel jQuery Plugin
 */
(function( $ ){

$.fn.infiniteCarousel = function(options) {
	
	// Extend our default options with those provided.
	var opts = $.extend({}, $.fn.infiniteCarousel.defaults, options);
	
	// Repeat Function
	function repeat(str, num) {
		return new Array( num + 1 ).join( str );
	}
  
  return this.each(function () {
  	
  	// Save our object
  	var $this = $(this);
  	
  	// Build element specific options
  	// This lets me access options with this syntax: o.optionName
  	var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
		
  	// Initialize Element Specific Variables
    var $wrapper = $this.find('.wrapper'),
    		$slider = $wrapper.find('> ul').addClass('slider'),
    		$items = $slider.find('> li').addClass('item'),
    		$single = $items.filter(':first'),
        
    		$singleWidth = $single.outerWidth(),
    		$visibleWidth = Math.ceil($wrapper.width() / $singleWidth),
    		$visible = Math.ceil($wrapper.width() / $singleWidth),
        
    		$currentPage = 1,
    		$pages = Math.ceil($items.length / $visible),
        
				$sliderWidth = ($wrapper.innerWidth() * 2) + ($wrapper.innerWidth() * $pages);
		
		$wrapper.css('overflow', 'hidden');
		$slider.css('width', $sliderWidth).attr('id', 'page-' + $currentPage);
		
    // 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 item" />', $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 item'));
    $items.filter(':last').after($items.slice(0, $visible).clone().addClass('cloned item'));
    $items = $slider.find('> li'); // reselect
    
    // 3. Set the left position to the first 'real' item
    $wrapper.scrollLeft($singleWidth * $visibleWidth);
        
		// 4. paging function
		function gotoPage(page) {
				
			var dir = page < $currentPage ? -1 : 1,
					n = Math.abs($currentPage - page),
					left = $singleWidth * dir * $visibleWidth * n;
			
			$wrapper.filter(':not(:animated)').animate({
				scrollLeft : '+=' + left
			}, 500, function () {
				if (page == 0) {
					$wrapper.scrollLeft($singleWidth * $visibleWidth * $pages);
					page = $pages;
				} else if (page > $pages) {
					$wrapper.scrollLeft($singleWidth * $visibleWidth);
					// reset back to start position
					page = 1;
				} 
				
			$currentPage = page;
						
			$slider.attr('id', 'page-' + $currentPage);
			$this
				.find('.' + o.dotNavClass + ' a')
				.removeClass('active')
			$this
				.find('.' + o.dotNavClass + ' a[href="#page-'+ $currentPage +'"]')
				.addClass('active');
	
			});
			
			return false;
		}
    
    // Switch every couple seconds
		function autoScroll() {
	    intervalID = setInterval(function() {
	      gotoPage($currentPage + 1);
			}, o.autoRotateSpeed);
			return intervalID;
		}
		
		if (o.autoRotate) {
		
			var intervalID = autoScroll();
			
			$this.hover(function() {
				clearInterval(intervalID);
			}, function() {
				clearInterval(intervalID);
				intervalID = autoScroll();
			});
		
		}
        
    // Add Navigation
    if (o.leftRightNav) {
			if (o.navContainer) {
				if (o.leftNav) $this.find('.' + o.navContainer).append('<span class="' + o.leftRightNavClass + ' ' + o.leftNavClass + '"></span>');
	    	if (o.rightNav) $this.find('.' + o.navContainer).append('<span class="' + o.leftRightNavClass + ' ' + o.rightNavClass + '"></span>');
			} else {
	    	if (o.leftNav) $wrapper.after('<span class="' + o.leftRightNavClass + ' ' + o.leftNavClass + '"></span>');
	    	if (o.rightNav) $wrapper.after('<span class="' + o.leftRightNavClass + ' ' + o.rightNavClass + '"></span>');
    	}
		}
    if (o.navContainer) {
			if (o.dotNav) $this.find('.' + o.navContainer).append('<div class="' + o.dotNavClass + '"></div>');
    } else {
			if (o.dotNav) $wrapper.after('<div class="' + o.dotNavClass + '"></div>');
		}

    for (var i = 1; i < ($pages + 1); i++ ) {
			$(this)
				.find('.' + o.dotNavClass)
				.append('<a href="#page-' + i + '">' + i + '</a>');
		}
		$(this)
			.find('.' + o.dotNavClass + ' a[href="#page-' + $currentPage + '"]')
			.addClass('active');
        
    // Bind to the forward and back buttons
    $('.' + o.leftNavClass, this).click(function () {
			return gotoPage($currentPage - 1);                
    });
    
    $('.' + o.rightNavClass , this).click(function () {
			return gotoPage($currentPage + 1);
    });
    
    // Bind to the Dot Navigation
    $('.' + o.dotNavClass + ' a', this).click(function() {
			return gotoPage( $(this).text() );
		});
    
    // create a public interface to move to a specific page
    $(this).bind('infiniteCarousel.goto', function (event, page) {
        gotoPage(page);
    });
    
  });
  
};

/**
 * Plugin Defaults
 */
$.fn.infiniteCarousel.defaults = {
	autoRotate : true,
	autoRotateSpeed : 5000,
	
	navContainer: false,
	
	leftRightNav : true,
	leftNav		: true,
	rightNav	: true,
	
	leftRightNavClass : 'nav-item',
	leftNavClass : 'nav-left',
	rightNavClass : 'nav-right',
	
	dotNav 		: true,
	dotNavClass : 'nav-dot'
};

})( jQuery );
