// Carousel Plugin //

(function ($) {
    var settings = {
        fadeDuration: 300,
        slideDelay: 10000,
        pagers: true,
        prevNextButtons: '.prevNext',
        nextClass: 'next',
        carouselClass: 'carousel',
        sliderEl: 'li',
        activeClass: 'active'
    };

    $.fn.carousel = function (defaults) {
        var defaults = $.extend({}, settings, defaults),
            data = {
                activeTransition: false,
                timeout: ''
            }
        root = $(this),
            carousel = root.find('.' + defaults.carouselClass),
            sliders = carousel.find(defaults.sliderEl);
			$.fn.carousel.animations = setAnimations();

        init();

        // Fades out the current slide and fades in the new one
        function fadeSliders(slideObj) {		
            data.activeTransition = true;
			
			if (typeof($.fn.carousel.animations[slideObj.currentID + 'Out']) == 'function' && typeof($.fn.carousel.animations[slideObj.nextID + 'In']) == 'function') {
				customTransitions(slideObj);
			} else {
				defaultTransitions(slideObj);
			}
			
			changePagers(sliders.index(slideObj.next));							
        }
		
		function customTransitions(slideObj) {
			slideObj.callback = function(slideObj) {
				$.fn.carousel.animations[slideObj.nextID + 'In'](slideObj);
				slideObj.active.removeClass(defaults.activeClass);		
				slideObj.next.addClass(defaults.activeClass);
				data.activeTransition = false;
			}
			
			$.fn.carousel.animations[slideObj.currentID + 'Out'](slideObj);
		}
		
		function defaultTransitions(slideObj) {
            slideObj.active.fadeOut(defaults.fadeDuration, function () {
                slideObj.active.removeClass(defaults.activeClass);
				data.activeTransition = false;
            });
            slideObj.next.fadeIn(defaults.fadeDuration, function () {
                slideObj.next.addClass(defaults.activeClass);
				data.activeTransition = false;
            });		
		}

        // Returns an object containing the current active slider and the
        // slider we'll transition to.
        function setSliders(type) {
            var obj = {};
            obj.active = carousel.find('.' + defaults.activeClass);

            if (type == defaults.nextClass) {
                obj.next = obj.active.next().length ? obj.active.next() : sliders.eq(0);
            } else {
                obj.next = obj.active.prev().length ? obj.active.prev() : sliders.eq(sliders.length - 1);
            }
			
            return attachElIds(obj);
        }
		
		function attachElIds(obj) {
			obj.currentID = obj.active.attr('id'),
			obj.nextID = obj.next.attr('id');

			return obj;
		}

        // Recursive timeout for automatic carousel rotation.
        function rotateCarousel(type) {
            clearTimeout(data.timeout);

            if (!type || type == 'undefined') {
                data.timeout = setTimeout(function () {
                    fadeSliders(setSliders('next'));
                    rotateCarousel();
                }, defaults.slideDelay);
            }
        }
		
		function fireInitialTransition() {		
			var next = sliders.eq(0),
				obj = {
					next: next,
					nextID: next.attr('id')
				}
				
			if (typeof($.fn.carousel.animations[obj.nextID + 'In']) == 'function') {
				$.fn.carousel.animations[obj.nextID + 'In'](obj);
			}
			
			next.addClass(defaults.activeClass);
		}

        // Constructs the markup for the pagers
        function buildPagers() {
            if (defaults.pagers) {
                var pagers = [];

                for (i = 0; i < sliders.length; i++) {
                    var page = i + 1;
                    i == 0 ? state = ' class="' + defaults.activeClass + '"' : state = '';

                    pagers.push('<li><a' + state + ' rel="' + page + '">' + page + '</a></li>')
                }

                return pagers.join('');
            }
        }

        // Attaches pagers to the DOM
        function renderPagers() {
            if (sliders.length > 1) {
                var pagers = '<ol class="pagers">' + buildPagers() + '</ol>';

                root.append(pagers);
                $(defaults.prevNextButtons).show();
            }
        }

        // Delegated event to transition slide on pager clicks
        function handlePagerClicks() {
            var pagers = $('.pagers').find('a');

            pagers.live('click', function () {
                var root = $(this);

                if (!root.hasClass(defaults.activeClass) && !data.activeTransition) {
                    var index = parseInt(root.attr('rel')) - 1,
                        obj = {};
                    obj.active = carousel.find('.' + defaults.activeClass);
                    obj.next = carousel.find(defaults.sliderEl).eq(index);
					
                    fadeSliders(attachElIds(obj));
                    rotateCarousel('pager');
                }
            });
        }

        // Event handler for prev/next button clicks
        function handlePrevNextClicks() {
            root.find(defaults.prevNextButtons).find('a').click(function (e) {
                e.preventDefault();

                if (!data.activeTransition) {
                    var root = $(this),
                        type = root.parents('li').attr('class'),
                        obj = setSliders(type);

                    fadeSliders(obj);
                    rotateCarousel('pager');
                }
            });
        }

        // Event handler to pause carousel rotation on hover
        function handleHovers() {
            root.hover(function () {
                rotateCarousel('pause');
            }, function () {
                rotateCarousel();
            });
        }

        // Updates the pagers to display the currently active selection
        function changePagers(index) {
            var pagers = root.find('.pagers'),
                active = pagers.find(defaults.sliderEl).eq(index).find('a');

            pagers.find('.' + defaults.activeClass).removeClass(defaults.activeClass);
            active.addClass(defaults.activeClass);
        }

        // Initializes the carousel
        function init() {
            renderPagers();
            handlePagerClicks();
            handlePrevNextClicks();
			fireInitialTransition();
            rotateCarousel();
        }
    };
})(jQuery);

