(function ($) {
	var aux = {
		// navigates left / right
		navigate: function (dir, $el, $wrapper, opts, cache) {

			var scroll = opts.scroll,
					factor = 1,
					idxClicked = 0;

			if (cache.expanded) {
				scroll = 1; // scroll is always 1 in full mode
				factor = 3; // the width of the expanded item will be 3 times bigger than 1 collapsed item	
				idxClicked = cache.idxClicked; // the index of the clicked item
			}

			// clone the elements on the right / left and append / prepend them according to dir and scroll
			if (dir === 1) {
				$wrapper.find('div.ca-item:lt(' + scroll + ')').each(function (i) {
					$(this).clone(true).css('left', (cache.totalItems - idxClicked + i) * cache.itemW * factor + 'px').appendTo($wrapper);
				});
			}
			else {
				var $first = $wrapper.children().eq(0);

				$wrapper.find('div.ca-item:gt(' + (cache.totalItems - 1 - scroll) + ')').each(function (i) {
					// insert before $first so they stay in the right order
					$(this).clone(true).css('left', -(scroll - i + idxClicked) * cache.itemW * factor + 'px').insertBefore($first);
				});
			}

			// animate the left of each item
			// the calculations are dependent on dir and on the cache.expanded value
			$wrapper.find('div.ca-item').each(function (i) {
				var $item = $(this);
				$item.stop().animate({
					left: (dir === 1) ? '-=' + (cache.itemW * factor * scroll) + 'px' : '+=' + (cache.itemW * factor * scroll) + 'px'
				}, opts.sliderSpeed, opts.sliderEasing, function () {
					if ((dir === 1 && $item.position().left < -idxClicked * cache.itemW * factor) || (dir === -1 && $item.position().left > ((cache.totalItems - 1 - idxClicked) * cache.itemW * factor))) {
						// remove the item that was cloned
						$item.remove();
					}
					cache.isAnimating = false;
				});
			});

		},
		// opens an item (animation) -> opens all the others
		openItem: function ($wrapper, $item, opts, cache) {
			cache.idxClicked = $item.index();
			// the item's position (1, 2, or 3) on the viewport (the visible items) 
			cache.winpos = aux.getWinPos($item.position().left, cache);
			$wrapper.find('div.ca-item').not($item).hide();
			$item.find('div.ca-content-wrapper').css('left', cache.itemW + 'px').stop().animate({
				width: cache.itemW * 2 + 'px',
				left: cache.itemW + 'px'
			}, opts.itemSpeed, opts.itemEasing)
				.end()
				.stop()
				.animate({
					left: '0px'
				}, opts.itemSpeed, opts.itemEasing, function () {
					cache.isAnimating = false;
					cache.expanded = true;

					aux.openItems($wrapper, $item, opts, cache);
				});

		},
		// opens all the items
		openItems: function ($wrapper, $openedItem, opts, cache) {
			var openedIdx = $openedItem.index();

			$wrapper.find('div.ca-item').each(function (i) {
				var $item = $(this),
						idx = $item.index();

				if (idx !== openedIdx) {
					$item.css('left', -(openedIdx - idx) * (cache.itemW * 3) + 'px').show().find('div.ca-content-wrapper').css({
						left: cache.itemW + 'px',
						width: cache.itemW * 2 + 'px'
					});

					// hide more link
					aux.toggleMore($item, false);
				}
			});
		},
		// show / hide the item's more button
		toggleMore: function ($item, show) {
			(show) ? $item.find('a.ca-more').show() : $item.find('a.ca-more').hide();
		},
		// close all the items
		// the current one is animated
		closeItems: function ($wrapper, $openedItem, opts, cache) {
			var openedIdx = $openedItem.index();

			$openedItem.find('div.ca-content-wrapper').stop().animate({
				width: '0px'
			}, opts.itemSpeed, opts.itemEasing)
				.end()
				.stop()
				.animate({
					left: cache.itemW * (cache.winpos - 1) + 'px'
				}, opts.itemSpeed, opts.itemEasing, function () {
					cache.isAnimating = false;
					cache.expanded = false;
				});

			// show more link
			aux.toggleMore($openedItem, true);

			$wrapper.find('div.ca-item').each(function (i) {
				var $item = $(this),
						idx = $item.index();

				if (idx !== openedIdx) {
					$item.find('div.ca-content-wrapper').css({
						width: '0px'
					})
						.end()
						.css('left', ((cache.winpos - 1) - (openedIdx - idx)) * cache.itemW + 'px')
						.show();

					// show more link
					aux.toggleMore($item, true);
				}
			});
		},
		// gets the item's position (1, 2, or 3) on the viewport (the visible items)
		// val is the left of the item
		getWinPos: function (val, cache) {
			switch (val) {
				case 0: return 1; break;
				case cache.itemW: return 2; break;
				case cache.itemW * 2: return 3; break;
			}
		}
	},
		methods = {
			init: function (options) {

				if (this.length) {

					var settings = {
						sliderSpeed: 500, 		// speed for the sliding animation
						sliderEasing: 'easeOutExpo', // easing for the sliding animation
						itemSpeed: 500, 		// speed for the item animation (open / close)
						itemEasing: 'easeOutExpo', // easing for the item animation (open / close)
						scroll: 1				// number of items to scroll at a time
					};

					return this.each(function () {

						// if options exist, lets merge them with our default settings
						if (options) {
							$.extend(settings, options);
						}

						var $el = $(this),
							$wrapper = $el.find('div.ca-wrapper'),
							$items = $wrapper.children('div.ca-item'),
							cache = {};

						// save the with of one item	
						cache.itemW = $items.width();
						// save the number of total items
						cache.totalItems = $items.length;

						// add navigation buttons
						if (cache.totalItems > 3)
							$el.prepend('<div class="ca-nav"><span class="ca-nav-prev">Previous</span><span class="ca-nav-next">Next</span></div>')

						// control the scroll value
						if (settings.scroll < 1)
							settings.scroll = 1;
						else if (settings.scroll > 3)
							settings.scroll = 3;

						var $navPrev = $el.find('span.ca-nav-prev'),
							$navNext = $el.find('span.ca-nav-next');

						// hide the items except the first 3
						$wrapper.css('overflow', 'hidden');

						// the items will have position absolute 
						// calculate the left of each item
						$items.each(function (i) {
							$(this).css({
								position: 'absolute',
								left: i * cache.itemW + 'px'
							});
						});

						// click to open the item(s)
						$el.find('a.ca-more').live('click.contentcarousel', function (event) {
							if (cache.isAnimating) return false;
							cache.isAnimating = true;
							$(this).hide();
							var $item = $(this).closest('div.ca-item');
							aux.openItem($wrapper, $item, settings, cache);
							return false;
						});

						// click to close the item(s)
						$el.find('a.ca-close').live('click.contentcarousel', function (event) {
							if (cache.isAnimating) return false;
							cache.isAnimating = true;
							var $item = $(this).closest('div.ca-item');
							aux.closeItems($wrapper, $item, settings, cache);
							return false;
						});

						// navigate left
						$navPrev.bind('click.contentcarousel', function (event) {
							if (cache.isAnimating) return false;
							cache.isAnimating = true;
							aux.navigate(-1, $el, $wrapper, settings, cache);
						});

						// navigate right
						$navNext.bind('click.contentcarousel', function (event) {
							if (cache.isAnimating) return false;
							cache.isAnimating = true;
							aux.navigate(1, $el, $wrapper, settings, cache);
						});

						// adds events to the mouse
						$el.bind('mousewheel.contentcarousel', function (e, delta) {
							if (cache.totalItems > 3) { // PK: added: only mousewheel support if totalitems > 3
								if (delta > 0) {
									if (cache.isAnimating) return false;
									cache.isAnimating = true;
									aux.navigate(-1, $el, $wrapper, settings, cache);
								}
								else {
									if (cache.isAnimating) return false;
									cache.isAnimating = true;
									aux.navigate(1, $el, $wrapper, settings, cache);
								}
							} // PK: end if()
							return false;
						});

					});
				}
			}
		};

	$.fn.contentcarousel = function (method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		} else {
			$.error('Method ' + method + ' does not exist on jQuery.contentcarousel');
		}
	};

})(jQuery);
