/**
 *  ///// Antistatique.net
 *  Portfolio AS Slider
 *  
 * @author Gilles Doge <gde@antistatique.net>
 * @copyright Antistatique.net Sàrl, 2009, All Right Reserved. 
 * @version 0.9 - $Id$
 * @required jQuery 1.2
 */

var ASSlider = (function($){
   
   var S = function(obj, settings)
   {
      this.settings = jQuery.extend({
         easeFunc: "easeInOutExpo",
         easeTime: 750,
         rotate: true,
         fixWidth: null,
         fixHeight: null,
         cb_onchange: null // callback onchange (with params: current, toIndex)
      }, settings);
      
      this.obj         = $(obj);
      this.pictWidth   = 0;
      this.pictHeight  = 0;
      this.pictEls     = 0;
      this.viewerWidth = 0;
      this.cursor      = 0;
      this.init();
   }; 
   
   S.prototype.init = function()
   {
      this.obj.removeClass("svw").addClass("stripViewer");
 
      this.pictWidth   = (this.settings.fixWidth !== null) ? this.settings.fixWidth : this.obj.find("li img").width();
      this.pictHeight  = (this.settings.fixHeight !== null) ? this.settings.fixHeight : this.obj.find("li img").height();
      this.pictEls     = this.obj.find("li").size();
      this.viewerWidth = this.pictWidth*this.pictEls;
      
      this.obj.find("ul").css({
         'width': this.viewerWidth,
         'height': this.pictHeight
      });
      this.obj.css("width", this.pictWidth).css("height", this.pictHeight);
      
      this.obj.find("ul li")
         // set the current item
         .removeClass("current").filter(":first").addClass("current").end()
         // add index attributes
         .each(function(i) { $(this).attr('index', i); });
      // init cursor
      this.cursor = 0;
   };
   
   /**
    * Go to the item #index (start at 0)
    *
    * @param integer index  index of the destination image
    * @param string withRotatingDirection  (optional) [left|right] if true, active the infinity algorithm algorithm
    *                              (the next image will always appear on the right, and the previous image on the left)
    */
   S.prototype.goTo = function(index, withRotatingDirection)
   {
      if(index < 0 || index >= this.pictEls) {
         return false;
      }
      if(typeof withRotatingDirection == "undefined") {
         withRotatingDirection = false;
      }
      // do animation
      this._animate(index, withRotatingDirection);
      this.cursor = index;
   };
   
   /**
    * Go to the next item
    */
   S.prototype.next = function()
   {
      var toIndex = (this.cursor+1) % this.pictEls;

      if(!this.settings.rotate)
      {
         this.goTo(toIndex);
      }
      else
      {
         this.goTo(toIndex, 'left')
      }
   };
   
   /**
    * Go to the previous item
    */
   S.prototype.prev = function()
   {
      var toIndex = (this.cursor > 0) ? this.cursor-1 : this.pictEls-1;
      
      if(!this.settings.rotate)
      {
         this.goTo(toIndex);
      }
      else
      {
         this.goTo(toIndex, 'right');
      }
   };
   
   
   /**
    * @visibility private.
    * do the cool job of motion.
    *
    * @param int toIndex
    * @param string rotating [left|right] rotate item before animate in the specified direction.
    */
   S.prototype._animate = function(toIndex, rotating){
      
      var offset  = -this.getPosLeft(toIndex);
      var ul      = this.obj.find("ul");
      var shifted = false;
      
      // Rotate
      if(this.settings.rotate && rotating) {
         var maxIndex = this.pictEls-1;
         // left rotating
         if('left' == rotating && this.cursor == maxIndex && toIndex == 0) {
            // copy the first item at the end of the list (for fluid anim)
            ul.css('width', (this.viewerWidth+this.pictWidth)+'px').append(
               ul.find('li:first').clone().removeClass('current').removeAttr('index')
            );
            
            offset  = -(this.pictWidth*this.pictEls);
            shifted = 'left';
         }
         // right rotating
         else if('right' == rotating && this.cursor == 0 && toIndex == maxIndex) {
            // copy the last item at the begin
            ul.css('width', (this.viewerWidth+this.pictWidth)+'px')
              .css('left', -this.pictWidth)
              .prepend(
                 ul.find('li:last').clone().removeClass('current').removeAttr('index')
               );
            
            offset  = 0;
            shifted = 'right';
         }
      }
      
      var self = this;
      ul.animate({ left: offset }, this.settings.easeTime, this.settings.easeFunc, function(){
         
         if(self.settings.rotate){
            if(shifted == 'left'){
               // reset the position to the first item and remove the temporary item.
               ul.css('left', '0px').find('li:last').remove().end().css('width', self.viewerWidth+'px');
               
            } else if(shifted == 'right'){
               // reset the position to the last item and remove the temporary item.
               ul.find('li:first').remove().end()
                 .css({
                    'left': -self.pictWidth*maxIndex,
                    'width': self.viewerWidth+'px'
                 });
            }
         }
         
         // define and change the current item
         var current = ul.find("li").removeClass("current").filter("[index='"+toIndex+"']").addClass("current");
         
         // call the 'onchange' callback if exist
         if(typeof self.settings.cb_onchange == "function") {
            self.settings.cb_onchange.call(this, current, toIndex);
         }
      });
   }
   
   // Get the left position offset from index number
   // NOTE: not really useful actually...
   S.prototype.getPosLeft = function(index)
   {
      var obj = this.obj.find("ul li[index='"+index+"']");
      if(obj.size() == 0)
      {
         return false;
      }
      
      return obj.position().left;
   }
   
   return S;
})(jQuery);