/* 
Carousel Plugin for JQuery Tools Scrollable
Copyright (c) 2010 Marcello Cosentino (cosentino DOT marcello AT gmail DOT com)

24-08-2010 */

/**
* Extends the jquery.tools scrollable plugin creating a carousel effect by keeping track of the active item.
* 
* The css class 'active' is added to the current item.
* 
* Note: this plugin works together with the scrollable plugin, as shown below.
*
* @name jScrollPane
* @type jQuery
* @param Object	settings	object with options, described below.
*								autoplay	    -	Whether to start the carousel (default: true).
*								interval		-	How long (in milliseconds) each item has to be shown (default: 5000).
*								detailselector	-	Optional jQuery selector of the html element that will contain the details of the active carousel item (default: null. no details)
*								itemcontentselector	-	Optional jQuery selector of the html element (initially hidden) with the item details (default: '.itemContent').
*														
*								transitionspeed	-	Speed of the FadeIn & FadeOut animations that eventually hide & shows the details of the active item
*
* Example 1:
*
*				<!-- optional browse links -->
*				<div class="browse">
*					<a class="prevC">prev</a>
*					<a class="playC">play</a>
*					<a class="stopC">stop</a>
*					<a class="nextC">next</a>
*				</div>
*				
*				<div class="scrollable">
*					<div class="items">
*						<div class="item"> Item 1</div>
*						<div class="item"> Item 2</div>
*						<div class="item"> Item 3</div>
*						<div class="item"> Item 4</div>
*					</div>
*				</div>
*
* @example $(".scrollable").scrollable().carousel();
*
*
* Example 2: Each time the active item change, the corresponding details (see itemcontentselector) will be copied inside the details container (see detailselector).
*
*			<div>
*               <div class="detailsContainer"></div>
*
*				<div class="scrollable">
*					<div class="items">
*						<div class="item"> 
*							Item 1							
*                           <div class="itemContent">Item 1 Details</div>
*						</div>
*						<div class="item">
*							Item 2
*                           <div class="itemContent">Item 2 Details</div>
*						</div>
*						<div class="item">
*							Item 3
*                           <div class="itemContent">Item 3 Details</div>
*						</div>
*						<div class="item">
*							Item 4
*                           <div class="itemContent">Item 4 Details</div>
*						</div>
*					</div>
*				</div>
*			<div>
*
* @example $(".scrollable")
*	.scrollable()
*	.carousel({detailselector:'.detailsContainer', itemcontentselector:'.itemContent'});
*
*/

(function ($) {

	var t = $.tools.scrollable;

	t.carousel = {
		conf: {
			autoplay: true,
			autostop: true,
			interval: 5000,
			transitionspeed: 500,
			detailselector: null,
			itemcontentselector: '.itemContent',
			prev: '.prevC',
			next: '.nextC',
			play: '.playC',
			stop: '.stopC'
		}
	};

	function find(root, query) {
		var el = $(query);
		return el.length < 2 ? el : root.parent().find(query);
	}

	// jQuery plugin implementation
	$.fn.carousel = function (conf) {

		if (typeof conf == 'number') {
			conf = { interval: conf };
		}

		var opts = $.extend({}, t.carousel.conf, conf), ret;

		this.each(function () {

			var c = $(this);

			var api = $(this).data('scrollable');
			if (api) { ret = api; }

			var items, currentIndex = -1, stopped = true, timer;

			// next/prev buttons
			var prevButton = find(c, opts.prev).click(function () {
					api.stopCarousel();
					api.prevCarousel();
			}),
				nextButton = find(c, opts.next).click(function () {
					api.stopCarousel();
					api.nextCarousel();
				}),
				playButton = find(c, opts.play).click(function () {
					api.playCarousel();
				}),
				stopButton = find(c, opts.stop).click(function () {
					api.stopCarousel();
				});

			//methods
			api.initCarousel = function () {
				//get the items
				items = api.getItems();

				//move the details of each items in the detail container
				if (opts.detailselector != null) {
					var detailContainer = $(opts.detailselector);
					items.each(function () {
						var itemDetailContent = $(this).children(opts.itemcontentselector);
						detailContainer.append(itemDetailContent.detach());
					});
				}

				//if the container for the item detail is specified
				if (opts.detailselector != null) {

					//handle the click on an item
					items.click(function (e) {
						api.seekToCarousel($(this).index());
						if (opts.autostop) {
							api.stopCarousel();
						}
						e.preventDefault();
					});

				}

				//mousewheel handler
				api.getRoot().mousewheel(function (e, delta) {
					api.seekToCarousel(currentIndex -= delta);
					e.preventDefault();
				});
			};
			
			api.playCarousel = function () {
				//if it's already running do nothing
				if (!stopped) { return; }

				//enable/disable the play and the stop buttons
				playButton.addClass('disabled');
				stopButton.removeClass('disabled');

				//start the carousel
				stopped = false;
				api.nextCarousel();
			};

			api.stopCarousel = function () {
				clearTimeout(timer);
				stopped = true;

				//enable/disable the play and the stop buttons
				stopButton.addClass('disabled');
				playButton.removeClass('disabled');
			};

			api.prevCarousel = function () {
				api.seekToCarousel(currentIndex - 1);
			};

			api.nextCarousel = function () {
				api.seekToCarousel(currentIndex + 1);
			};

			api.seekToCarousel = function (index) {
				currentIndex = index;

				//implement the circularity of the carousel
				currentIndex = currentIndex % Math.max(api.getVisibleItems().size(), api.getSize());
				if (currentIndex < 0)
					currentIndex = api.getSize() + currentIndex;

				//run the animation
				api.updateActiveItem();
			}

			//set the active class on the next item and trigger the event
			api.updateActiveItem = function () {
				//keep running
				if (!stopped) {
					clearTimeout(timer);
					timer = setTimeout(function () {
						api.nextCarousel();
					}, opts.interval);
				}

				//set the class active on the correct item
				api.getItems().removeClass('active');
				var currentItem = api.getItems().eq(currentIndex);
				currentItem.addClass('active');

				//trigger the event before the animation starts
				c.trigger('onBeforeActivateItem', [currentItem]);

				//scroll to the active item if it's the next element is not visible
				if (api.getSize() > api.getVisibleItems().size() && currentIndex % api.getVisibleItems().size() == 0)
					api.seekTo(currentIndex, api.getConf().speed);

				//run the animation that shows the detail of the active item
				if (opts.detailselector != null) {
					var detailContainer = $(opts.detailselector);
					var details = detailContainer.children(opts.itemcontentselector);

					//hide the item details
					details.fadeOut(opts.transitionspeed);

					//show just the details of the active item
					details.eq(currentIndex).fadeIn(opts.transitionspeed, function () {
						//trigger the event at the end of the animation
						c.trigger('onActivateItem', [currentItem]);
					});

				} else {

					//just trigger the event
					c.trigger('onActivateItem', [currentItem]);
				}
			};

			//init the carousel
			api.initCarousel();

			//run it now
			if (conf.autoplay) {
				api.playCarousel();
			}

		});

		return opts.api ? ret : this;
	}

})(jQuery);
