jQuery.fn.infiniteCarousel = function() {
  return this.each(function() {
    var wrapper = jQuery(this),
      slider = wrapper.find('.items'),
      viewer = wrapper.find('.viewer'),
      items = slider.find('.item'),
      single = items.filter(':first'),
      
    singleWidth = single.outerWidth(margin=true),
    
    visible = Math.ceil(viewer.innerWidth() / singleWidth),
    currentPage = 1,
    pages = Math.ceil(items.length / visible);
    
    if (items.length <= 1) { return false; } // If there's only one story, stop the script
    
    items.each(function (i) {
      var class_name = 'index-' + (i + 1);
      jQuery(this).addClass(class_name);
    });
    
    items.click(function (e) {
      var index = jQuery(this).attr("class");
      var bits = index.split(' ');
      
      for (var i=0; i < bits.length; i++) {
        if (bits[i].match('index-')) {
          var index = bits[i].split('index-');
          index = index[1];
        }
      };
      
      index = Number(index);
      
      if (currentPage != index) { e.preventDefault(); }
      
      if ((currentPage == 1) && (index == pages)) {
        previous(e);
      } else if ((currentPage == pages) && (index == 1)) {
        next(e);
      } else {
        if (currentPage < index) {
          next(e);
        } else if (currentPage > index) {
          previous(e);
        }
      }
    });
    
    items.filter(':first').before(items.slice(-visible - 1).clone(true).addClass('cloned'));
    items.filter(':last').after(items.slice(0, visible + 1).clone(true).addClass('cloned'));
    items.find('.item');
    
    var scroll = singleWidth * (visible + 1);
    wrapper.scrollLeft(scroll); // reset slider position to the first REAL item
    
    wrapper.bind('next', next);
    wrapper.bind('previous', previous);
    wrapper.bind('select_thumbnail', handle_thumbs);
    wrapper.bind('select_item', active_item);
    
    function next(e) {
      e.preventDefault();
      wrapper.trigger('goto', [(currentPage + 1)]);
    }
    
    function previous(e) {
      e.preventDefault();
      wrapper.trigger('goto', [(currentPage - 1)]);
    }
    
    function gotoPage(page) {
      var direction = page < currentPage ? -1 : 1,
        n = Math.abs(currentPage - page),
        left = singleWidth * direction * visible * n;
      
      wrapper.filter(':not(:animated)').animate({
        scrollLeft : '+=' + left
      }, 500, function() {
        if (page == 0) {
          var scroll_it = singleWidth * visible * (pages + 1);
          
          wrapper.scrollLeft(scroll_it);
          page = pages;
        } else if (page > pages) {
          wrapper.scrollLeft(singleWidth * (visible + 1));
          page = 1;
        }
        
        currentPage = page;
        
        jQuery(this).trigger('select_item', [currentPage]);
        jQuery(this).trigger('select_thumbnail', [currentPage]);
      });  
      
      return false;
    }
    
    function active_item(e, currentPage) {
      var all_items = jQuery('.items .item');
      all_items.removeClass('selected').removeClass('fade').each(function (i) {
        total_items = items.length;
        index = i - 1;
        
        if (currentPage == index) {
          jQuery(this).addClass('selected');
        } else {
          jQuery(this).addClass('fade');
        }
      });
    }
    
    function handle_thumbs(e, page) {
      var thumbs = jQuery('.carousel_navigation .thumb');
      thumbs.removeClass('selected').each(function (i) {
        index = i + 1;
        
        if (page == index) {
          jQuery(this).addClass('selected');
        }
      });
      
      thumbs.click(function (e) {
        e.preventDefault();
        var index = thumbs.index(this) + 1;
        wrapper.trigger('goto', [index]);
      });
    }
    
    var first_nav_item = jQuery('.carousel_navigation li').filter(':first');
    var last_nav_item = jQuery('.carousel_navigation li').filter(':last');
    jQuery('<li><a class="arrow back">Previous</a></li>').insertBefore(first_nav_item);
    jQuery('<li><a class="arrow forward">Next</a></li>').insertAfter(last_nav_item);
    
    jQuery('.carousel_navigation a.back').click(previous);
    jQuery('.carousel_navigation a.forward').click(next);
    
    jQuery(this).bind('goto', function(event, page) {
      gotoPage(page);
    });
    
    wrapper.trigger('goto', [currentPage]);
  });
};
