/**
 * Wayfarer Carousel
 * Version 0.9.6
 * Author Abel Mohler
 * URI: http://www.wayfarerweb.com/wcarousel.php
 * Released with the MIT License: http://www.wayfarerweb.com/mit.php
 */

/**
 * Based on jCarouselLite (modified and improved)
 *
 * http://gmarwaha.com/jquery/jcarousellite/
 *
 * Copyright (c) 2007 Ganeshji Marwaha (gmarwaha.com)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Version: 1.0.1
 */
(function($) {                                          // Compliant with jquery.noConflict()
    $.fn.wCarousel = function(o, callback) {
        o = $.extend({
            prev: null,
            next: null,
            hoverToMove: false,
            btnGo: null,
            mouseWheel: false,
            auto: null,

            speed: 200,
            pause: 0,//only for use with hoverToMove
            easing: null,

            vertical: false,
            circular: true,
            visible: 3,
            start: 0,
            scroll: 1,

            callBefore: null,
            callAfter: null
        }, o || {});

        if (typeof callback == "function")
            o.callAfter = callback;

        var talk = (typeof $.talk == "function" && typeof $.listen == "function") ? true : false;

        if(talk) {
            o.plugin = "wCarousel";
            o.channel = "wayfarer";
            o.key = this;
            $.talk(o);
        }

        return this.each(function() {                           // Returns the element collection. Chainable.

            var running = false, timer = {}, animCss = (o.vertical) ? "top" : "left", sizeCss = (o.vertical) ? "height" : "width";
            var div = $(this), ul = $(">ul", div), tLi = $(">li", ul), tl = tLi.size(), v = o.visible;

            if(o.circular) {
                ul.prepend(tLi.slice(tl - v - 1 + 1).clone())
                .append(tLi.slice(0, v).clone());
                o.start += v;
            }

            var li = $(">li", ul), itemLength = li.size(), curr = o.start;
            div.css("visibility", "visible");

            li.css({
                overflow: "hidden",
                "float": (o.vertical) ? "none" : "left"
                });
            ul.css({
                margin: "0",
                padding: "0",
                position: "relative",
                "list-style-type": "none",
                "z-index": "1"
            });
            div.css({
                overflow: "hidden",
                position: "relative",
                "z-index": "2",
                left: "0px"
            });

            var liSize = o.vertical ? height(li) : width(li);   // Full li size(incl margin)-Used for animation
            var ulSize = liSize * itemLength;                   // size of full ul(total length, not just for the visible items)
            var divSize = liSize * v;                           // size of entire div(total length for just the visible items)

            li.css({
                width: li.width(),
                height: li.height()
                });
            ul.css(sizeCss, ulSize + "px").css(animCss, -(curr*liSize));

            div.css(sizeCss, divSize + "px");                     // Width of the DIV. length of visible images

            if(o.prev)
                if(!o.hoverToMove) {//default action
                    $(o.prev).click(function() {
                        return go(curr - o.scroll);
                    });
                }
                else {
                    $(o.prev).hover(function() {
                        go(curr - o.scroll);
                        timer = setInterval(function(){
                            go(curr - o.scroll);
                        }, o.speed + o.pause);
                    }, function() {
                        clearTimeout(timer);
                    })
                }

            if(o.next)
                if(!o.hoverToMove) {//default action
                    $(o.next).click(function() {
                        go(curr + o.scroll);
                    });
                }
                else {
                    $(o.next).hover(function() {
                        go(curr + o.scroll);
                        timer = setInterval(function(){
                            return go(curr + o.scroll);
                        }, o.speed + o.pause);
                    }, function() {
                        clearTimeout(timer);
                    })
                }

            if(o.btnGo)
                $.each(o.btnGo, function(i, val) {
                    $(val).click(function() {
                        return go(o.circular ? o.visible + i : i);
                    });
                });

            if(o.mouseWheel && div.mousewheel)
                div.mousewheel(function(e, d) {
                    return (d > 0) ? go(curr - o.scroll) : go(curr + o.scroll);
                });

            if(o.auto)
                setInterval(function() {
                    go(curr + o.scroll);
                }, o.auto + o.speed);

            function vis() {
                return li.slice(curr).slice(0,v);
            };

            function go(to) {
                if(!running) {

                    if(typeof o.callBefore == "function") {
                        o.callBefore.call(this, vis(), o);
                        if(talk) o = $.listen(o);
                    }

                    if(o.circular) {            // If circular we are in first or last, then goto the other end
                        if(to < 0) {           // If first, then goto last //(bug fix: if(to<=o.start-v-1) becomes if(to<0)

                            ul.css(animCss, -((itemLength-(v * 2)) * liSize) + "px");
                            // If "scroll" > 1, then the "to" might not be equal to the condition; it can be lesser depending on the number of elements.
                            curr = (to == o.start - v - 1) ? itemLength - (v * 2) - 1 : itemLength - (v * 2) - o.scroll; //itemLength-(v*2)-1 became itemLength-(v*2)-v
                        } else if(to >= itemLength - v + 1) { // If last, then goto first
                            ul.css(animCss, -( (v) * liSize ) + "px" );
                            // If "scroll" > 1, then the "to" might not be equal to the condition; it can be greater depending on the number of elements.
                            curr = (to == itemLength - v + 1) ? v + 1 : v + o.scroll;
                        } else curr = to;
                    } else {                    // If non-circular and to points to first or last, we just return.
                        if(to < 0 || to > itemLength - v) return;
                        else curr = to;
                    }                           // If neither overrides it, the curr will still be "to" and we can proceed.

                    running = true;

                    ul.animate(
                        animCss == "left" ? {
                            left: -(curr * liSize)
                        } : {
                            top: -(curr * liSize)
                        } , o.speed, o.easing,
                        function() {
                            if(typeof o.callAfter == "function") {
                                o.callAfter.call(this, vis(), o);
                                if(talk) o = $.listen(o);
                            }
                            running = false;
                        }
                        );
                    // Disable buttons when the carousel reaches the last/first, and enable when not
                    if(!o.circular) {
                        $(o.prev + "," + o.next).removeClass("disabled");
                        $( (curr - o.scroll < 0 && o.prev)
                            ||
                            (curr + o.scroll > itemLength - v && o.next)
                            ||
                            []
                            ).addClass("disabled");
                    }

                }
                return false;
            };
        });
    };

    function css(el, prop) {
        return parseInt($.css(el[0], prop)) || 0;
    };
    function width(el) {
        return  el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
    };
    function height(el) {
        return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
    };
})(jQuery);


