/*
Title :: adidoCarousel
Author :: Thomas Stradling
Version :: 0.3.9

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.

0.3.2a ::

 - Added option: pagerHover (boolean | false)
   If this is enabled when a user hovers over a pager element it will become the active
   element, and will select the corresponding carousel item.

0.3.3 ::

 - Rewritten passing through extra variables to the moveCarousel function using an array.
 - Rewritten fade animation, more natural effect.
   Includes an initial setup for fade animation allowing for the different.
 
 - Various parts of this release are still being worked on.
    - pagerHoverAnimations
    - pagerHover bugs
    
 - Added option: pagerAnim (boolean | false)
   Replaces previous pager animation options. Setting to true causes all aspects of
   pager to animate.
   
0.3.4 ::

 - Added option: dynamicResize (boolean | false)
 
0.3.5 ::

0.3.6 ::
0.3.6 - pre 1 ::
0.3.6 - pre 2 ::
0.3.6 - pre 3 ::
0.3.6 - pre 4 ::
0.3.6 - pre 5 ::
  - Added custom option for declaring next/previous buttons.
    Allows for buttons relative to the root element.
  
  - Added animInstant to the initial setup section.
    If the startPosition is non-standard shifts the carousel to the appropriate starting position.
0.3.6 - pre 6 ::
  - Added custom option for declaring pager item.
    Allows for pager element selection relative to the root element.
    
0.3.7 ::
   0.3.6 Compilation
   
   - Added extra option for pagerStyle : image
     Searches carousel element for an image with the .pagerImg class.
     Then adds to the corresponding pager element.
     
   - Added extra animation option (loop)
   
   - Reworked pager selection. Now based off value stored in 'rel'.
   
0.3.9 ::
  - Changed the custom pager/button method.
    Now a function is passed as an argument.
    i.e. pagerElement: function(e){ return pager; }
    
0.3.10 ::
  - Added new animation: slideFade.
  - Last item trigger added

0.3.11 ::
  - Added new option: buttonHide
*/

//
(function($) {
    //
    $.fn.adidoCarousel = function(options) {
        var opts = $.extend({}, $.fn.adidoCarousel.defaults, options);
        return this.each(function() {
            jQuery.easing.def = opts.anim;
            var $this = $(this);

            $this.addClass('aCarousel');

            /* 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;
            /* Rotation count */var r = r - (-1 + opts.minDisplay);

            /* info array */
            var _info = new Array();
            _info['lc'] = lc;
            _info['c'] = c;
            _info['os'] = os;
            _info['r'] = r;

            if (opts.horizontal) {
                var d = 'left';
                var ls = $this.children('li').eq(0).outerWidth(true);
                if (opts.mode == "loop") {
                    $this.width((lc * ls) * 2);
                } else {
                    $this.width(lc * ls);
                }
            } else {
                var d = 'top';
                var ls = $this.children('li').eq(0).outerHeight();
                $this.height(lc * ls);
            }

            _info['ls'] = ls;

            /* Modify size of the list */
            lc = lc - (-1 + opts.minDisplay);
            _info['lc'] = lc;

            if (opts.autoStart && _info['lc'] > 1) {
                if (opts.startDelay > 0) {
                    var t = setTimeout(function() {
                        var carouselTimer = setInterval(function() {
                            if (c < r) {
                                c += opts.step;
                            } else {
                                c = opts.startPosition;
                            }
                            _info['dir'] = 'next';
                            $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                        }, opts.speed);
                    }, opts.startDelay);
                } else {
                    var carouselTimer = setInterval(function() {
                        if (c < r) {
                            c += opts.step;
                        } else {
                            c = opts.startPosition;
                        }
                        _info['dir'] = 'next';
                        $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                    }, opts.speed);
                }
            }

            if (opts.buttons) {

                var btnNextType = typeof (opts.buttonNext);
                if (btnNextType == "function") {
                    var $btnNext = opts.buttonNext($this);
                } else {
                    var $btnNext = $(opts.buttonNext);
                }

                $btnNext.click(function(e) {
                    e.preventDefault();

                    carouselTimer = window.clearInterval(carouselTimer);

                    if (opts.clickContinue) {
                        carouselTimer = setInterval(function() {
                            if (c < r) {
                                c += opts.step;
                            } else {
                                c = opts.startPosition;
                            }
                            _info['dir'] = 'next';
                            $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                        }, opts.speed);
                    }

                    if (c < r) {
                        c += opts.step;
                    } else {
                        c = opts.startPosition;
                    }
                    _info['dir'] = 'next';
                    $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                });

                var btnPrevType = typeof (opts.buttonPrev);
                if (btnPrevType == "function") {
                    var $btnPrev = opts.buttonPrev($this);
                } else {
                    var $btnPrev = $(opts.buttonPrev);
                }

                $btnPrev.click(function(e) {
                    e.preventDefault();

                    carouselTimer = window.clearInterval(carouselTimer);

                    if (opts.clickContinue) {
                        carouselTimer = setInterval(function() {
                            if (c < r) {
                                c += opts.step;
                            } else {
                                c = opts.startPosition;
                            }
                            _info['dir'] = 'next';
                            $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                        }, opts.speed);
                    }

                    if (c > opts.startPosition) {
                        c -= opts.step;
                    } else {
                        c = r;
                    }
                    _info['dir'] = 'prev';
                    $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                });
		
		if (opts.buttonHide) {
                    if (_info['lc'] > 1) {
                        $btnNext.show();
                        $btnPrev.show();
                    } else {
                        $btnNext.hide();
                        $btnPrev.hide();
                    }
                }

            }

            if (opts.pager) {
                // Build a pager system for the carousel
                // Assigns the selector to a variable allowing easier access / faster performance(?).

                var pagerType = typeof (opts.pagerElement);

                if (pagerType == 'function') {
                    var $pager = opts.pagerElement($this);
                } else {
                    var $pager = $(opts.pagerElement);
                }
                _info['pager'] = $pager;
                
                if (opts.pagerHide) {
		    if (_info['lc'] > 1) {
			$pager.show();
		    } else {
			$pager.hide();
		    }
                }

                // 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++) {
                        var ps = '';
                        var li = $('<li></li>');
                        li.attr('rel', i);
                        switch (opts.pagerStyle) {
                            case null:
                                ps = '';
                                break;
                            case 'numeric':
                                psi = i + 1;
                                ps = '' + psi;
                                li.text(ps);
                                break;
                            case 'image':
                                $this.children('li:eq(' + i + ')').find('img.pagerImg').clone().appendTo(li);
                                break;
                            default:
                                ps = '';
                        }
                        $pager.children('ul').append(li);
                    }
                } else {
                    $pager.find('li').each(function() {
                        var i = $(this).index();
                        $(this).attr('rel', i);
                    });
                }
                // 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() {
                    carouselTimer = window.clearInterval(carouselTimer);

                    if (opts.clickContinue) {
                        carouselTimer = setInterval(function() {
                            if (c < r) {
                                c += opts.step;
                            } else {
                                c = opts.startPosition;
                            }
                            _info['dir'] = 'next';
                            $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                        }, opts.speed);
                    }
                    // Prevents jumping behaviour clicking on an item which is currently active.
                    if ($(this).hasClass('acpActive')) {
                        // Do Nothing
                    } else {
                        c = $(this).attr('rel');
                        c = parseInt(c);
                        c = c + 1;
                        _info['dir'] = 'next';
                        $.fn.adidoCarousel.moveCarousel($this, c, _info, opts);
                    }
                }).css('cursor', 'pointer');

                // If custom pager element uses <a> tag as part of the mark up disable 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).outerHeight();
                    if (hh > h) {
                        h = hh;
                    }
                }).height(h);
                $this.parent().height(h);
                if (!opts.horizontal) {
                    _info['ls'] = h;
                }
            }

            if (opts.hoverPause) {
                $this.parent().hover(function() {
                    $this.addClass('hover');
                }, function() {
                    $this.removeClass('hover');
                });
            }

            if (opts.dynamicResize) {
                var h = $this.children('li:nth-child(' + c + ')').height();
                $this.parent().height(h);
            }

            /* Initial item setup */
            $this.children('li:nth-child(' + c + ')').addClass('acActive');

            switch (opts.mode) {
                case 'fade':
                    var fadeCSS = {
                        'left': '0',
                        'position': 'absolute',
                        'top': '0',
                        'z-index': '2'
                    };
                    $this.children('li').css(fadeCSS).hide();
                    $this.children('li:nth-child(' + c + ')').css('z-index', '6').show();
                    break;
            }
            $.fn.adidoCarousel.animInstant($this, c, _info, opts);
        });
    };

    $.fn.adidoCarousel.defaults = {
        anim: 'easeInOutExpo',
        animCallback: function(e, c, _a, o) { /* Code Goes Here */ },
        animDelay: 600,
        animSpeed: 400,
        autoStart: true,
        buttons: true,
	    buttonHide: false,        
	    buttonNext: '.carouselNext',
        buttonPrev: '.carouselPrev',
        clickContinue: false,
        dynamicResize: false,
        horizontal: true,
        hoverPause: false,
        imgLarge: false,
        imgContainer: '.imgContainer',
        minDisplay: 1,
        mode: 'slide',
        pager: false,
        pagerAuto: true,
        pagerElement: '.carouselPager',
        pagerHide: false,
        pagerMove: false,
        pagerStyle: 'none',
        pagerAnim: false,
        resizeMask: false,
        speed: 5000,
        startDelay: 0,
        startPosition: 1,
        step: 1,
        wrap: false
    };

    $.fn.adidoCarousel.moveCarousel = function(e, c, _a, o) {
        _a['current'] = e.children('.acActive').index();

        e.children('.acActive').removeClass('acActive');
        e.children('li:nth-child(' + c + ')').addClass('acActive');
        switch (o.mode) {
            case 'slide':
                $.fn.adidoCarousel.animSlide(e, c, _a, o);
                break;

            case 'fade':
                $.fn.adidoCarousel.animFade(e, c, _a, o);
                break;

            case 'instant':
                $.fn.adidoCarousel.animInstant(e, c, _a, o);
                break;

            case 'loop':
                $.fn.adidoCarousel.animLoop(e, c, _a, o);
                break;

            case 'slideFade':
                $.fn.adidoCarousel.animSlideFade(e, c, _a, o);
                break;

            case 'custom':
                $.fn.adidoCarousel.animCustom(e, c, _a, o);
                break;

            default:
                /* If value is over-ridden with an incorrect mode it defaults to using 'slide' animation method */
                $.fn.adidoCarousel.animSlide(e, c, _a, o);
        }
        if (o.pager) {
            $.fn.adidoCarousel.movePager(o, c, _a);
        }
        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);
        }
        if (o.dynamicResize) {
            var h = e.children('li:nth-child(' + c + ')').height();
            e.parent().height(h);
        }

    }

    $.fn.adidoCarousel.animFade = function(e, c, _a, o) {
        e.children('li').fadeOut(o.animSpeed);
        e.children('li:nth-child(' + c + ')').hide().css('z-index', 6).delay(o.animDelay).fadeIn(o.animSpeed, $.fn.adidoCarousel.animCallback(e, c, _a, o));
    }

    $.fn.adidoCarousel.animInstant = function(e, c, _a, o) {
        s = _a['ls'];
        if (o.horizontal) {
            e.css({
                left: -((c - 1) * s) + "px"
            });
            $.fn.adidoCarousel.animCallback(e, c, _a, o);
        } else {
            e.css({
                top: -((c - 1) * s) + "px"
            });
            $.fn.adidoCarousel.animCallback(e, c, _a, o);
        }
    }

    $.fn.adidoCarousel.animLoop = function(e, c, _a, o) {
        var s = _a['ls'];
        if (_a['dir'] == 'next') {
            e.stop().animate({ left: -s + "px" }, o.animSpeed, function() {
                e.children().first().appendTo(e);
                e.css({ left: 0 });
                $.fn.adidoCarousel.animCallback(e, c, _a, o);
            });
        } else {
            e.css({ left: -s }).children().last().prependTo(e);
            e.stop().animate({ left: 0 }, o.animSpeed, function() {
                $.fn.adidoCarousel.animCallback(e, c, _a, o);
            });
        }


    }

    $.fn.adidoCarousel.animSlide = function(e, c, _a, o) {
        s = _a['ls'];
        if (o.horizontal) {
            e.stop().animate({
                left: -((c - 1) * s)
            }, o.animSpeed, $.fn.adidoCarousel.animCallback(e, c, _a, o));
        } else {
            e.stop().animate({
                top: -((c - 1) * s)
            }, o.animSpeed, $.fn.adidoCarousel.animCallback(e, c, _a, o));
        }
    }

    $.fn.adidoCarousel.animSlideFade = function(e, c, _a, o) {
        var s = _a['ls'];
        if (o.horizontal) {
            e.stop().animate({
                left: -((c - 1) * s)
            }, o.animSpeed, function() {
                //e.css({ opacity: 1 });
                $.fn.adidoCarousel.animCallback(e, c, _a, o);
            });
        } else {
            e.stop().animate({
                top: -((c - 1) * s)
            }, o.animSpeed, function() {
                // e.css({ opacity: 1 });
                $.fn.adidoCarousel.animCallback(e, c, _a, o);
            });
        }
        var current = _a['current'] + 1;
        e.children('li:nth-child(' + current + ')').siblings().css({ opacity: 0 }).end().animate({ opacity: 0 }, o.animSpeed).siblings(':nth-child(' + c + ')').delay(o.animDelay).animate({ opacity: 1 }, o.animSpeed);
    }

    $.fn.adidoCarousel.movePager = function(o, c, _a) {
        var $e = _a['pager'];
        $e.find('.acpActive').removeClass('acpActive');
        $e.find('.acpNext').removeClass('acpNext');
        var n = c + 1;
        if (o.pagerAnim) {
            $e.find('li:nth-child(' + n + ')').addClass('acpNext', 500);
            $e.find('li:nth-child(' + c + ')').addClass('acpActive', 500);
        } else {
            $e.find('li:nth-child(' + n + ')').addClass('acpNext');
            $e.find('li:nth-child(' + c + ')').addClass('acpActive');
        }

        if (o.mode == "loop") {
            $e.children('li').removeClass('acpActive, acpNext');
            $e.children('li').first().addClass('acpActive');
        }
    }
    
    $.fn.adidoCarousel.btnNext = function(e) {
        return btn;
    }
    
    $.fn.adidoCarousel.btnPrev = function(e) {
        return btn;
    }
    
    $.fn.adidoCarousel.pager = function(e) {
        return pager;
    }
    
    $.fn.adidoCarousel.setupLinear = function(e) {
    }

    $.fn.adidoCarousel.setupStack = function(e) {
    }

    $.fn.adidoCarousel.animCallback = function(e, c, _a, o) {
        o.animCallback(e, c, _a, o);
    }

    $.fn.adidoCarousel.animCustom = function(e, c, s, o) {
        // e : plugin element
        // c : item count
        // s : element size
        // o : options
    }
    //
})(jQuery);
//
