


(function($){ $.fn.arturoSlider = function(options){

// configuration properties
options = $.extend({
 // defaults
 auto: true,
 speed: 500,
 easing: "swing",
 wrap: true,
 autoPreserveDirection: false,
 period: 5000,
 hoverPause: true,
 onBeforeChange: null,
 onStep: null,
 onAfterChange: null
},
options);

this.each(function(){



 /* === SETUP ELEMENTS AND VARIABLES ================================= */


 var $slider = $(this);
 var $slidees = options.slidees || $slider.children();

 // set up max width slide rail
 $slidees.wrapAll("<div></div>");
 var $rail = $slidees.parent();

 // find slide parent dimensions
 var width = $slider.innerWidth();

  $rail.css({
   width: $slidees.length * width
  });

 // captions
 var $captions = options.captions || {};



 /* === SLIDE ANIMATION AND TRACKING ================================= */


 // Tracking of how many there are and what we're on right now
 var numSlidees = $slidees.length;
 var currentSlidee = 0;
 var currentSlideeNum = 0;

 // logic and animation for moving between elements
 function slide(arg){

  // If already sliding, ignore the request and dump out
  if($rail.filter(":animated").length > 0) return false;

  // if it's a boolean it represents forwards (true) or backwards (false)
  var slideTo = arg;
  var direction; // true=forward, false=backward
  var wrap = null;

  if(typeof(slideTo) == "boolean"){
   slideTo = currentSlidee + (arg ? 1 : -1);
   if(options.wrap){
    slideTo = (slideTo >= numSlidees+1 || slideTo < -1) ? 0 : slideTo;
    if(slideTo >= numSlidees){
     slideTo = 0;
     wrap = true;
    }
    else if(slideTo < 0){
      slideTo = numSlidees-1;
      wrap = false;
    }
   }else{
    slideTo = (slideTo >= numSlidees) ? 0 : slideTo;
    slideTo = (slideTo < 0) ? numSlidees-1 : slideTo;
   }
   auto.direction(arg);
  }
  else{
    auto.direction((slideTo > currentSlideeNum) ? true : false);
   slideTo = original2dom(slideTo);
  }


  // set new current slidee and if we're trying to slide to the slide we're already on, give up and return false
  if(slideTo == currentSlidee){
   return false;
  }
  currentSlidee = slideTo;


  // reorder the slidees if necessary to enable wrapping
  if(wrap === true){
   $rail
    .append( $rail.children(":first") )
    .css({
     marginLeft: -(width*(numSlidees-2))
    });
   slideTo = numSlidees-1;
  }
  else if(wrap === false){
   $rail
    .prepend( $rail.children(":last") )
    .css({
     marginLeft: -(width)
    });
   slideTo = 0;
  }

  // Call event function
  if(typeof(options.onBeforeChange) === "function"){ options.onBeforeChange(dom2original(slideTo)); }

  // do the actual main animation by sliding the rail they live in left or right
  $rail
  .stop()
  .animate(
   {marginLeft: -(width*slideTo)},
   {
    easing: options.easing,
    duration: options.speed,
    complete: function(){
     if(typeof(options.onAfterChange) === "function"){ options.onAfterChange(dom2original(slideTo)); }
     if(options.auto) auto.q();
     // undo the reordering
     if(wrap === true){
      $rail
       .append( $rail.children(":not(:last)") )
       .css({
        marginLeft: -(width*currentSlidee)
       });
     }
     else if(wrap === false){
      $rail
       .prepend( $rail.children(":not(:first)") )
       .css({
        marginLeft: -(width*currentSlidee)
       });
     }
    },
    step: options.onStep
   }
  );

  if($captions.length > 0){
   $captions
   .stop()
   .filter(":visible")
    .fadeOut(
     options.speed/2,
     (function(slideTo){
      return function(){
       $captions
       .slice(currentSlidee, currentSlidee + 1)
        .fadeIn(options.speed/2);
      }
     })(slideTo)
    );
  }


  // if numbers list exists, highlight the new current one halfway through the transition
  if($numbers && $numbers.length > 0){
   setTimeout(
    function(){
     $numbers
     .removeClass("current")
     .slice(currentSlidee,currentSlidee+1)
      .addClass("current");
    },
    options.speed/2
   );
  }


 }/*slide(arg)*/


 function dom2original(domPosition){
  var $slidee = $rail.children().slice(domPosition, domPosition+1)
  var out = $slidees.index($slidee);
  return out;
 }

 function original2dom(originalPosition){
  var $slidee = $slidees.slice(originalPosition, originalPosition+1)
  var out = $rail.children().index($slidee);
  return out;
 }


 /* === AUTO PROCEED ================================================= */


 var auto = new function(){
  var _that = this;
  var _direction = true; // true = forward, false = backward
  var _timer;
  var _pause = false;

  if(options.hoverPause){
   $slider.hover(
    function(){
     _that.pause(true);
    },
    function(){
     _that.pause(false);
    }
   )
  }

  this.q = function(){
   clearTimeout(_timer);
   if(!_pause){
    _timer = setTimeout(
     function(){
      slide(options.autoPreserveDirection?_direction:true);
     },
     options.period
    );
   }
  }

  this.direction = function(newDirection){
   if(typeof(newDirection) != "boolean"){
    return _direction;
   }
   else{
    _direction = newDirection;
   }
  }

  this.pause = function(pause){
   if(typeof(pause) != "boolean"){
    return _pause;
   }
   else{
    _pause = pause;
    if(pause){
     clearTimeout(_timer);
    }
    else{
     this.q();
    }
   }
  }

 }/*auto()*/

 if(options.auto){
  auto.q();
  // define some events for other scripts to pause/resume externally
  $slider
   .bind("arturoSliderPause", function(){
    auto.pause(true);
   })
   .bind("arturoSliderResume", function(){
    auto.pause(false);
   });
  }


 /* === EVENT HANDLING =============================================== */


 // first/prev/next/last controls click handlers config
 var controls = [
  ["first", 0],
  ["prev", false],
  ["next", true],
  ["last", numSlidees-1]
 ];

 for(var i in controls){
  var cID = options[controls[i][0]+"ID"];
  if(cID){
   $("#"+cID).click(
    (function(arg){
     // generic click handler for first/prev/next/last
     return function(ev){
      slide(arg);
      $(this).blur();
      ev.preventDefault();
     }
    })(controls[i][1])
   )
  }
 }

 // click handler for the numbers is a bit different!
 var $numbers;
 if(options.listID){
  $numbers = $("#"+options.listID).find("a");
  $numbers.click(function(ev){
   slide($numbers.index(this));
   $(this).blur();
   ev.preventDefault();
  });
 }

});

}})(jQuery)
