﻿
(function($) {
   $.fn.jac = function(options) {
      var opts = $.extend({}, $.fn.jac.defaults, options);

      return this.each(function() {             //Iterate and construct the carousel
         var $vp = $(this);
         var $vpw = Math.round($vp.width());
         var $c = $vp.children("ul:only-child");
         if ($c.length > 1) return;             //Only supports one carousel per viewport

         var settings = $.meta ? $.extend({}, opts, $vp.data()) : opts;
         var sel = {                            //Create selectors
            carouselSelector: "." + settings.carouselSelector,
            childSelector: "." + settings.childSelector,
            leftArrowSelector: "." + settings.leftArrowSelector,
            rightArrowSelector: "." + settings.rightArrowSelector
         };

         // Setup the CSS and wrap the carousel
         $vp.addClass("jac")
			   .children("ul")
	         .addClass(settings.carouselSelector)
	         .children("li")
	         .addClass(settings.childSelector);
         $c.wrapAll(
		       $("<div class='carousel-wrapper'></div>")
		       .css({
		          "overflow": "hidden",
		          "width": $vpw,
		          "height": $vp.height(),
		          "position": "relative"
		       })
		   );
         $c.css("width", getCarouselWidth() + "px");

         if (getCarouselWidth() <= $vpw) return;       //Bypass the movement if everything is already displayed 

         var childWidth = $c.find(sel.childSelector + ":eq(0)").width();
         var kidsPerView = Math.floor($vpw / childWidth);

         // EnableMouse support - moves content to center of mouse cursor (where it entered hover)
         $c.find(sel.childSelector)
		      .hover(function(e) {       //mouseover
		         if (!settings.enableMouse) return;

		         var myAbs;              //my abs pos to carousel
		         if (settings.childSizeFixed) {
		            myAbs = $c.children().index(this) * childWidth;
		         } else {
		            myAbs = Math.round($(this).position().left);
		         }
		         var myRel = myAbs + getCarouselPos();                    //my rel pos to viewport
		         var myAbsC = myAbs + Math.round($(this).width() / 2);    //my abs pos to carousel - centered
		         var mouseRelV = Math.round(e.pageX) - $vp.offset().left; //mouse rel to viewport
		         var mouseRelC = mouseRelV - myAbsC;                      //mouse rel to my center
		         var newPos = myAbsC - mouseRelV;                         //new position to move to
		         var newRelPosL = myAbs - newPos;                         //new rel position, left
		         var newRelPosR = $(this).width() + myAbs - newPos;
		         if (!settings.childFixedSize) newRelPosR += 1;           //compensate for $'s -1 off
		         // Keep from going outside the viewport
		         if (newRelPosL <= 0) newPos = newPos + newRelPosL;
		         if (newRelPosR >= $vpw) newPos = newPos + (newRelPosR - $vpw);

		         $c.stop().animate({     //Stop all animations (smoothly)
		            "left": -newPos
		         }, settings.childSlideSpeed, settings.easingStyle, onMoveFinished);
		      }, function(e) {         //mouseout            
		         if (!settings.enableMouse) return;
		         $c.stop();
		      });  //.hover			

         //Handle left and right arrow navigation
         if (getCarouselWidth() > $vpw) {
            $vp.append("<span class='" + settings.leftArrowSelector + "'></span>");
            $vp.append("<span class='" + settings.rightArrowSelector + "'></span>");

            //Left arrow    
            $vp.find(sel.leftArrowSelector)
		        .html("<a href='javascript:void(0)' title='" + settings.leftText + "'>" + settings.leftText + "</a>")
		        .css("opacity", 0.7)
		        .find("a")
		        .hover(function() { $(this).parent().fadeTo(settings.fadeSpeed, 1); }, function() { $(this).parent().fadeTo(settings.fadeSpeed, 0.7); })
		        .click(function() {
		           var movePos, newPos;
		           newPos = getCarouselPos() + $vpw;

		           if (checkReachedEdge("left")) { onMoveFinished(); return; }
		           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;
		           }
		           if (newPos > 0) {
		              movePos = -getCarouselPos();
		           }

		           movePos = movePos + getCarouselPos();

		           $c.stop();
		           $c.animate({
		              "left": movePos
		           }, settings.parentSlideSpeed, settings.easingStyle, onMoveFinished);
		        }); // left

            //Right arrow
            $vp.find(sel.rightArrowSelector)
		        .html("<a href='javascript:void(0)' title='" + settings.rightText + "'>" + settings.rightText + "</a>")
		        .css("opacity", 0.7)
		        .find("a")
		        .hover(function() { $(this).parent().fadeTo(settings.fadeSpeed, 1); }, function() { $(this).parent().fadeTo(settings.fadeSpeed, 0.7); })
		        .click(function() {
		           var movePos, newPos;
		           newPos = -getCarouselPos() + $vpw;

		           if (!settings.enableMouse && settings.childSizeFixed) {
		              movePos = kidsPerView * childWidth;
		           } else {
		              movePos = $vpw;
		           }


		           if (newPos >= getCarouselWidth() - $vpw) {
		              movePos = (getCarouselWidth() - $vpw) + getCarouselPos();
		           }

		           movePos = movePos - getCarouselPos();

		           $c.stop();
		           $c.animate({
		              "left": -movePos
		           }, settings.parentSlideSpeed, settings.easingStyle, onMoveFinished);
		        }); // 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();
            }
         } // navigation

         // Get the carousel width
         function getCarouselWidth() {
            var w = 0;

            if (settings.childFixedSize) {
               w = $c.find(sel.childSelector).length * childWidth;
            } else {
               $c.find(sel.childSelector).each(function() {
                  w += $(this).width();
               });
            }
            return w;
         }

         //When animation finishes, checks to see if carousel reached edge and hides/shows arrows
         function onMoveFinished() {

            if (checkReachedEdge("left")) {
               $vp.find(sel.leftArrowSelector).hide("normal");
            } else {
               $vp.find(sel.leftArrowSelector).show("normal");
            }
            if (checkReachedEdge("right")) {
               $vp.find(sel.rightArrowSelector).hide("normal");
            } else {
               $vp.find(sel.rightArrowSelector).show("normal");
            }
         }

         //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) + 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);
         }

      }); // 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
   }; // defaults

})(jQuery);   //End of closure
