﻿/*
* Just Another Carousel v1.0
* http://intrepidstudios.com/projects/jquery-just-another-carousel/
*
* Copyright (c) 2009 Kamran Ayub
* Licensed under the GPL license.
* http://intrepidstudios.com/projects/jquery-just-another-carousel/#license
*
* Last Modified: Feb 2, 2009
* This file is part of Just Another Carousel.

Just Another Carousel is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Just Another Carousel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Just Another Carousel.  If not, see <http://www.gnu.org/licenses/>.
*/
(function($) {
    $.fn.jac = function(options) {

        //
        // build main options before element iteration
        //
        var opts = $.extend({}, $.fn.jac.defaults, options);

        //
        // iterate and construct the carousel
        //
        return this.each(function() {

            // the viwport
            var $vp = $(this);
            var $vph;
            var $divPadding = 0;
            if ($(this).find('div').length != 0) {
                $divPadding = parseInt($(this).find('div:first').css('margin-right').replace('px', ''));
            }
            var $vpw = Math.round($vp.width());
            if ($('.' + this.className + ' div').length == 0) {
                $vph = $(this).height();
            }
            else {
                $vph = 0;
                var divs = $('.' + this.className + ' div');
                $.each(divs, function(i, val) {
                    var height = $(val).height();
                    if (height > $vph) {
                        $vph = height;
                    }
                });
            }
            if ($(this).hasClass('.list_holder')) {
                $vph = 0;
                var items = $(this).find('ul.list');
                $.each(items, function(i, val) {
                    var height = $(val).height();
                    if (height > $vph) {
                        $vph = height;
                    }
                });
            }
            var $vpw = Math.round($vp.width());
            var $c = $vp.children("ul:only-child");


            // Only support one carousel per viewport
            if ($c.length > 1) return;

            // element specific options
            var settings = $.meta ? $.extend({}, opts, $vp.data()) : opts;

            // selectors
            var sel = {
                carouselSelector: "." + settings.carouselSelector,
                childSelector: "." + settings.childSelector,
                leftArrowSelector: "." + settings.leftArrowSelector,
                rightArrowSelector: "." + settings.rightArrowSelector
            };
            var $noOfItems = getCarouselWidth() / $vpw
            //
            // Setup CSS
            //
            $vp
			.addClass("jac")
			.children("ul")
	        .addClass(settings.carouselSelector)
	        .children("li")
	        .addClass(settings.childSelector);
            // carousel wrapper
            $c.wrapAll(
		        $("<div class='carousel-wrapper'></div>")
		        .css({
		            "overflow": "hidden",
		            "width": $vpw,
		            "height": $vph,
		            "position": "relative"
		        })
		    );
            $c.css("width", getCarouselWidth() + "px");

            // Don't bother letting users move stuff if you can see everything
            if (getCarouselWidth() <= $vpw) return;

            // less processing to store a fixed width
            var childWidth = $c.find(sel.childSelector + ":eq(0)").width();
            var kidsPerView = Math.floor($vpw / childWidth);

            // 
            // Moves content to center of mouse cursor (where it entered hover)
            //
            $c
		    .find(sel.childSelector)
		    .hover(
		        function(e) {
		            if (!settings.enableMouse) return;

		            // my abs pos to carousel
		            var myAbs;

		            if (settings.childSizeFixed) {
		                myAbs = $c.children().index(this) * childWidth;
		            } else {
		                myAbs = Math.round($(this).position().left);
		            }

		            // my rel pos to viewport
		            var myRel = myAbs + getCarouselPos();

		            // my abs pos to carousel - centered
		            var myAbsC = myAbs + Math.round($(this).width() / 2);

		            // mouse rel to viewport
		            var mouseRelV = Math.round(e.pageX) - $vp.offset().left;

		            // mouse rel to my center
		            var mouseRelC = mouseRelV - myAbsC;

		            // new position to move to
		            var newPos = myAbsC - mouseRelV;

		            // new rel position, left
		            var newRelPosL = myAbs - newPos;
		            var newRelPosR = $(this).width() + myAbs - newPos;

		            // compensate for $'s -1 off
		            if (!settings.childFixedSize) newRelPosR += 1;

		            // Keep from going outside the viewport
		            if (newRelPosL <= 0) newPos = newPos + newRelPosL;
		            if (newRelPosR >= $vpw) newPos = newPos + (newRelPosR - $vpw);

		            // Stop all animations (smoothly)
		            $c.stop().animate({
		                "left": -newPos
		            }, settings.childSlideSpeed, settings.easingStyle, onMoveFinished);
		        },
		        function(e) {
		            if (!settings.enableMouse) return;

		            $c.stop();
		        });

            // 
            // Handle navigation
            //
            if (getCarouselWidth() > $vpw) {

                $vp.append("<span class='" + settings.leftArrowSelector + "'></span>");
                $vp.append("<span class='" + settings.rightArrowSelector + "'></span>");

                // left arrow
                $(sel.leftArrowSelector)
		        .click(function() {
		            if (!lock) {
		                lock = true;
		                var movePos, newPos;

		                newPos = getCarouselPos() + $vpw + $divPadding;

		                lastItem = getCurrentItem();


		                if (!settings.enableMouse && settings.childSizeFixed) {
		                    // move so we show equal amounts of kids at once
		                    // if the mouse is enabled, this wouldn't make sense
		                    movePos = kidsPerView * childWidth;
		                } else {
		                    // children are variable, so move viewport width
		                    movePos = $vpw + $divPadding;
		                }

		                if (newPos > 0) {
		                    movePos = -getCarouselPos();
		                    lastItem = 1;
		                }

		                movePos = movePos + getCarouselPos();
		                if (checkReachedEdge("left")) {
		                    movePos = (getCarouselWidth() - ($vpw + $divPadding)) * -1;
		                    lastItem = 1;
		                }


		                $c.stop();
		                $c.animate({
		                    "left": movePos
		                }, settings.parentSlideSpeed, settings.easingStyle, onMoveFinished);
		                if (settings.autoScroll) {
		                    autoMove();
		                }
		            }
		        }); // left

                var lock = false;

                // right arrow
                $(sel.rightArrowSelector)
		        .click(function() {
		            if (!lock) {
		                lock = true;
		                var movePos, newPos;
		                newPos = -getCarouselPos() + $vpw + $divPadding;
		                lastItem = getCurrentItem();
		                if (!settings.enableMouse && settings.childSizeFixed) {
		                    movePos = kidsPerView * childWidth;
		                } else {
		                    movePos = $vpw + $divPadding;
		                }


		                if (newPos >= getCarouselWidth() - $vpw) {
		                    movePos = (getCarouselWidth() - $vpw) + getCarouselPos() - $divPadding;
		                }

		                movePos = movePos - getCarouselPos();
		                if (checkReachedEdge("right")) {
		                    movePos = 0;
		                    lastItem = getCarouselWidth() / ($vpw + $divPadding);
		                }
		                $c.stop();
		                $c.animate({
		                    "left": -movePos
		                }, settings.parentSlideSpeed, settings.easingStyle, onMoveFinished);
		                if (settings.autoScroll) {
		                    autoMove();
		                }
		            }

		        }); // next

                // In case its decided that the carousel has a different
                // initial pos
                //				if(checkReachedEdge("left")) {
                //					$vp.find(sel.leftArrowSelector).hide();
                //				}
                //		
                //				if(checkReachedEdge("right")) {
                //					$vp.find(sel.rightArrowSelector).hide();
                //				}

                if (settings.autoScroll) {
                    autoMove();
                }
            } // navigation
            var autoTimer;
            function autoMove() {
                clearTimeout(autoTimer);
                autoTimer = window.setTimeout(function() {
                    $(sel.rightArrowSelector).click();
                }, settings.scrollAfter);
            }

            // Get the carousel width
            function getCarouselWidth() {
                var w = 0;

                // Get carousel width
                if (settings.childFixedSize) {
                    w = $c.find(sel.childSelector).length * childWidth;
                } else {

                    $c.find(sel.childSelector).each(function() {
                        w += $(this).width();
                    });

                }
                return w;
            }

            var currentItem;
            var lastItem;

            function showHideText(objIn, objOut) {

            }

            // When animation finishes, checks to see if carousel reached edge,
            // and hides/shows arrows
            function onMoveFinished() {
                lock = false;
                var newPosition = getCurrentItem();
                if (settings.textPrefix != '') {
                    if (newPosition != lastItem) {
                        $("#" + settings.textPrefix + lastItem).css('display', 'none');
                        $("#" + settings.textPrefix + newPosition).css('display', 'block');
                    }
                }
            }

            // Checks to see if the carousel
            // has reached an edge
            function checkReachedEdge(side) {
                switch (side) {
                    case "left":
                        if (Math.round(getCarouselPos()) >= 0) return true;
                        break;
                    case "right":
                        var rightEdge = Math.round((getCarouselWidth() - $vpw - $divPadding) + getCarouselPos());

                        if (rightEdge <= 0) return true;

                        break;
                }

                return false;
            }

            // For some reason, $'s position().left
            // is off by 1 pixel. So we get it from the CSS instead since that's
            // what we're manipulating.
            function getCarouselPos() {
                return getCssPos($c);
            }

            function getCurrentItem() {
                var currentPosition = getCarouselPos();
                return Math.ceil((-currentPosition / $vpw) + 1);
            }

        }); // return this.each

    }; // jac

    //
    // Returns a number for the CSS left position
    //
    function getCssPos(el) {
        var cssPos = $(el).css("left");

        return Math.round(parseInt(cssPos.replace("px", "")));
    }

    //
    // plugin defaults
    //
    $.fn.jac.defaults = {
        carouselSelector: "carousel",
        childSelector: "jac-content",
        leftArrowSelector: "arrow-left",
        rightArrowSelector: "arrow-right",
        easingStyle: "swing",
        rightText: "Next",
        leftText: "Previous",
        childSizeFixed: true,
        childSlideSpeed: 300,
        parentSlideSpeed: 600,
        fadeSpeed: 300,
        enableMouse: false,
        textPrefix: '',
        autoScroll: false,
        scrollAfter: 5000
    }; // defaults

    //
    // end of closure
    //
})(jQuery);