/*
Title :: adidoCarousel
Author :: Thomas Stradling
Version :: 0.3.1

Changelog ::

0.1 ::

Basic implementation of the solution.

 - Sliding carousel animation.
 - Allows the definition on animation style (default: easeInOutExpo).
 - Allows for use of next / previous buttons.
   Button use controlled by 'buttons' parameter (default: true)
   Also allows control over which elements are designated as buttons
   using buttonNext and buttonPrev parameters.
 - Added clickContinue option.
   Allows carousel to continue cycling after user clicks on a button
   when set to true (default: false).
 - Option speed
   Sets the pause between animations in miliseconds.

INCOMPLETE

 - buildFrameWork

0.2 ::

 - Added pager system
 - Option pagerElement
   Specifies an element containing a <ul> to be referenced.
 - Adds class 'aCarousel' to carousel item.

0.2.1 ::

 - Option startPosition
   Sets an offset for the carousel to start on.

0.3 ::

 - Added option: horizontal (boolean | true)
   Controls the direction of scrolling for the carousel.
   Default behaviour is horizontal scrolling.

 - Added new 'fade' animation.
 - Added option: mode (string | 'slide')
   Controls the animation method to use, currently either 'slide' or
   fade, if invalid value specified defaults to 'slide'.

 - adidoCarousel can now be used to power a image slide show.
   There should only be one image per <li> in the carousel.
   When the carousel moves it searches current <li> for an <img> and gets
   the src attribute, then transfers the src to the designated large
   image target.
 - Added option: imgLarge (boolean | false)
   Controls whether to use the slide show option.
 - Added option: imgContainer (string | '.imgContainer')
   Designates the element to be used for the large image.

 - Added option: step (integer | 1)
   Gives the option allowing the carousel to step through multiple slides
   at a time.

INCOMPLETE

wrap
   

0.3.1 ::

 - Using $pager to hold pagerElement jQuery object.
 - Added option: resizeMask (boolean | false)
   If enabled causes the parent of the plugin object to be resized
   according to the height of the tallest <li> item in the carousel
   list.

0.3.2 ::

 - Added option: hoverPause (boolean | false)
   When enabled pauses the carousel on a hover event and restarts it on the hover exit.

*/

//
(function($) {
    //
    $.fn.adidoCarousel = function(options) {
        var opts = $.extend({}, $.fn.adidoCarousel.defaults, options);
        return this.each(function() {
            jQuery.easing.def = opts.anim;
            var $this = $(this);

            /* List count */var lc = $this.children('li').size();
            /* Current item index */var c = opts.startPosition;
            /* Offset */var os = -1 + opts.step;
            /* Rotation count */var r = lc - os;

            if (opts.horizontal) {
                var d = 'left';
                var ls = $this.children('li').eq(0).outerWidth();
                $this.width(lc * ls);
            } else {
                var d = 'top';
                var ls = $this.children('li').eq(0).outerHeight();
                $this.height(lc * ls);
            }

            if (!$this.hasClass('aCarousel')) {
                $this.addClass('aCarousel');
            }

            var carouselTimer = setInterval(function() {
                if (c < r) {
                    c += opts.step;
                } else {
                    c = opts.startPosition;
                }
                $.fn.adidoCarousel.moveCarousel($this, c, ls, opts);
            }, opts.speed);

            if (opts.buttons) {
                $(opts.buttonNext).click(function(e) {
                    e.preventDefault();
                    if (!opts.clickContinue) {
                        clearInterval(carouselTimer);
                    }
                    if (c < r) {
                        c += opts.step;
                    } else {
                        c = opts.startPosition;
                    }
                    $.fn.adidoCarousel.moveCarousel($this, c, ls, opts);
                });
                $(opts.buttonPrev).click(function(e) {
                    e.preventDefault();
                    if (!opts.clickContinue) {
                        clearInterval(carouselTimer);
                    }
                    if (c > 1) {
                        c -= opts.step;
                    } else {
                        c = r;
                    }
                    $.fn.adidoCarousel.moveCarousel($this, c, ls, opts);
                });
            }

            if (opts.pager) {
                // Build a pager system for the carousel

                // Assigns the selector to a variable allowing easier access / faster performance(?).
                var $pager = $(opts.pagerElement);

                // Creates an un-ordered list automatically, and populates it with a <li> item for each <li> in the carousel.
                if (opts.pagerAuto) {
                    $pager.append('<ul></ul>');
                    var i = 0;
                    for (i = 0; i < lc; i++) {
                        $pager.children('ul').append('<li></li>');
                    }
                }
                // Initialises the pager elements when first loaded.
                var n = c + 1;
                $pager.find('li:nth-child(' + n + ')').addClass('acpNext');
                $pager.find('li:nth-child(' + c + ')').addClass('acpActive');

                $pager.find('li').click(function() {
                    if (!opts.clickContinue) {
                        clearInterval(carouselTimer);
                    }
                    c = $pager.find('li').index(this);
                    c += 1;
                    $.fn.adidoCarousel.moveCarousel($this, c, ls, opts);
                }).css('cursor', 'pointer');

                // If custom pager element uses <a> tag as part of the mark up disables default click.
                $pager.find('a').click(function(e) {
                    e.preventDefault();
                });
            }

            if (opts.imgLarge) {
                var src = $this.children('li:nth-child(' + c + ')').find('img').attr('src');
                if ($(opts.imgContainer).find('img').size() == 0) {
                    $(opts.imgContainer).append('<img />')
                }
                $(opts.imgContainer).find('img').attr('src', src);
            }

            if (opts.resizeMask) {
                var h = 0;
                $this.children('li').each(function() {
                    var hh = $(this).height();
                    if (hh > h) {
                        h = hh;
                    }
                });
                $this.parent().height(h);
            }

            if (opts.hoverPause) {
                $this.parent().hover(function() {
                    /*clearInterval(carouselTimer);*/
                    $this.addClass('hover');
                }, function() {
                    /*var carouselTimer = setInterval(function() {
                        if (c < r) {
                            c += opts.step;
                        } else {
                            c = opts.startPosition;
                        }
                        $.fn.adidoCarousel.moveCarousel($this, c, ls, opts);
                    }, opts.speed);*/
                    $this.removeClass('hover');
                });
            }

            /* Initial item setup */
            $this.children('li:nth-child(' + c + ')').addClass('acActive');
        });
    };

    $.fn.adidoCarousel.defaults = {
        anim: 'easeInOutExpo',
        buttons: true,
        buttonNext: '.carouselNext',
        buttonPrev: '.carouselPrev',
        clickContinue: false,
        horizontal: true,
        hoverPause: false,
        imgLarge: false,
        imgContainer: '.imgContainer',
        mode: 'slide',
        pager: false,
        pagerAuto: true,
        pagerElement: '.carouselPager',
        resizeMask: false,
        speed: 5000,
        startPosition: 1,
        step: 1,
        wrap: false
    };

    $.fn.adidoCarousel.moveCarousel = function(e, c, w, o) {
        e.children('.acActive').removeClass('acActive');
        e.children('li:nth-child(' + c + ')').addClass('acActive');
        switch (o.mode) {
            case 'slide':
                $.fn.adidoCarousel.animSlide(e, c, w, o);
                break;

            case 'fade':
                var l = c - 1;
                if (o.horizontal) {
                    var d = 'left';
                } else {
                    var d = 'top';
                }
                e.children('li:nth-child(' + c + ')').fadeOut(400, function() {
                    e.css(d, -((c - 1) * w) + 'px').children('li:nth-child(' + c + ')').fadeIn();
                });
                break;

            default:
                /* If value is over-ridden with an incorrect mode it defaults to using 'slide' animation method */
                $.fn.adidoCarousel.animSlide(e, c, w, o);
        }
        if (o.pager) {
            $.fn.adidoCarousel.movePager(o, c);
        }
        if (o.imgLarge) {
            var src = e.children('li:nth-child(' + c + ')').find('img').attr('src');
            if ($(o.imgContainer).find('img').size() == 0) {
                $(o.imgContainer).append('<img />')
            }
            $(o.imgContainer).find('img').attr('src', src);
        }

    }

    $.fn.adidoCarousel.animSlide = function(e, c, s, o) {
        if (o.horizontal) {
            e.animate({
                left: -((c - 1) * s) + "px"
            }, 500);
        } else {
            e.animate({
                top: -((c - 1) * s) + "px"
            }, 500);
        }
    }

    $.fn.adidoCarousel.movePager = function(o, c) {
        $e = $(o.pagerElement);
        $e.find('.acpActive').removeClass('acpActive');
        $e.find('.acpNext').removeClass('acpNext');
        var n = c + 1;
        $e.children('ul').children('li:nth-child(' + n + ')').addClass('acpNext');
        $e.children('ul').children('li:nth-child(' + c + ')').addClass('acpActive');
    }

    $.fn.adidoCarousel.buildFrameWork = function(e) {
        // var w = $('<div class="carouselContainer"><div class="carouselFrame"></div></div>');
        e.wrap('<div class="carouselFrame"></div>');
        e.parent().wrap('<div class="carouselContainer"></div>');
        var a = $('<a href="#prev" class="carouselPrev">Previous</a> <a href="#next" class="carouselNext">Next</a>');
        e.parent().parent().append(a);
    }
    //
})(jQuery);
//
