/****************************
 **
 **  svCarousel
 **  Version: 1.1a
 **  Author: Alberto Gasparin
 **  ©2010 Studio Visuale
 **
 ****************************/

;(function($) {
  
  $.fn.svCarousel = function(options, callback) {
    if(typeof options == 'function') {
      callback = options;
      options = null;
    }
    //eseguo il codice per ogni elemento che trovo
    return this.each(function() {
      var cb = (callback) ? callback : function(){};
      new $svc($(this), options, cb);
    });
  };
  
  var defaults = {
    autoplay: true,                         // autoplay all'avvio [bool] {true, false}
    keys : false,                           // bind dei tasti [bool] {true, false}
    interval: 4000,                         // intervallo [ms]
    transition: "fade",                     // tipo di transizione [string] {fade, crossFade, crossFade2, crossSlide}
    controls: 0,                            // tipo di controlli [int] {0: none, 1:only buttons, 2:buttons+text, 3: dots}
    controls_target: '',                    // elemento di riferimento per i controlli [jquery obj]
    controls_position: 'after',             // posizione dei controlli rispetto al target [string] {after, before, append}
    verso: 1,                               // direzione [int] {1, -1}
    in_time: 1000,                          // tempo transizione in [ms] (need for fade, crossFade, crossSlide)
    out_time: 500,                          // tempo transizione out [ms] (need for fade, crossFade, crossFade2)
    animate : {'height':'350px'}            // cosa animare [params] (need for crossSlide)
  }
  
  
  /*********************
    * The svCarousel object
    *********************/
  $.svCarousel = function($o, op, cb) {
    this.opts = $.extend({}, defaults, op || {});
    this.list = $o;
    this.cb = cb;
    
    if ($('.active', this.list).length != 1) {
      this.list.children(':first').addClass('active');
    }
    
    // setup elementi base
    if (this.list.css('position') != 'relative' && this.list.css('position') != 'absolute') // se l'oggetto non ha position
      this.list.css('position','relative');
    
    // conto quante immagini ho
    this.n = this.list.children().length;
    
    // se voglio i controlli ed ho + di un elemento
    if (this.opts.controls > 0 && this.n > 1) {
      if (this.opts.controls_target == '') // se non è stato settato
          this.ctrl_tgh = this.list;
      this._drawControls();
    }
    
    if (this.opts.keys)
        this._bindKeys();
    
    // inizio se autoplay e + di una foto
    if (this.opts.autoplay && this.n > 1)
        this._begin();
  }
  
  // Create shortcut for internal use
  var $svc = $.svCarousel;
  $svc.fn = $svc.prototype = {
    svCarousel: '1.0'
  };
  $svc.fn.extend = $svc.extend = $.extend;

  // Estensione di svCarousel con i metodi
  $svc.fn.extend({
    // Metodi interni all'oggetto
    _begin : function() {
      var oo = this;
      clearTimeout(this.t)
      if (this.opts.autoplay)
        this.t = setTimeout(function() { oo._draw() }, this.opts.interval);
    },
    
    _draw : function(n_to) {
      var $active = $('.active', this.list);
      var oo = this; // mi server per passarlo alle funzioni
      
      if (n_to) { // se ho specificato chi animare
        var $to_animate = this.list.children(':eq('+n_to+')');
      } else { // se non ho specificato
        if (this.opts.verso == 1) { // vado avanti
          if($active.next().length == 1) {
            var $to_animate = $active.next();
          } else {
            var $to_animate = this.list.children(':first');
          }
        } else { // vado indietro
          if ($active.prev().length == 1) {
            var $to_animate = $active.prev();
          } else {
            var $to_animate = this.list.children(':last');
          }
        }
      }
      
      switch (this.opts.transition) {
        case 'fade':
          $active.fadeOut(oo.opts.out_time, function() {
            // parte l'animazione
            $to_animate.fadeIn(oo.opts.in_time, function() {
              oo._end($to_animate);
            });
          });
          break;
        case 'crossFade':
          $active.fadeOut(oo.opts.out_time);
          $to_animate.fadeIn(oo.opts.in_time, function() {
              oo._end($to_animate);
          });
          break;
        case 'crossFade2':
          // imposto che quella attiva stia sopra
          $active.css('z-index',5).fadeOut(oo.opts.out_time, function() {
            oo._end($to_animate);
          });
          // mostro la slide successiva ma la metto sotto
          $to_animate.css('z-index',1).show();
          break;
        case 'crossSlide':
          $to_animate.animate(oo.opts.animate, oo.opts.in_time, function() {
            oo._end($to_animate);
          });
          break;
      }
    },
    
    _end : function(el) {
      // rendo attivo l'elemento
      this._setActive(el);
      // se ho i controlli
      if (this.opts.controls != 0 && this.n > 1)
          this._updateControls();
      // reimposto il timeout
      this._begin();
      // eseguo il callback con this = .active
      this.cb.call(el);
    },
    
    _drawControls : function() {
      var html = '<div class="svScorri">';
      switch(this.opts.controls) {
        case 1:
        case 2:
          html += '<b class="indietro"></b>'
            + '<a class="indietro" href="#" style="display: none;">prev</a>';
          if (this.opts.controls == 2)
              html+= '<span class="svNum">1</span><span class="svTot">/ '+this.n+'</span>'
          html+= '<a class="avanti" href="#">next</a>'
            + '<b class="avanti" style="display: none;"></b>';
          break;
        case 3:
          for (var i=1; i<=this.n; i++) {
            var css = (i==1) ? 'active' : '';
            html += '<a class="dot '+css+'" href="#'+(i-1)+'">'+i+'</a>';
          }
          break;
      }
      html += '</div>';
      
      // aggiungo i controlli alla pagina
      switch (this.opts.controls_position) {
        case 'append':
          $(this.ctrl_tgh).append(html);
          this.ctrl_el = this.ctrl_tgh;
          break;
        case 'after':
          $(this.ctrl_tgh).after(html);
          this.ctrl_el = $(this.ctrl_tgh).next();
          break;
        case 'before':
          $(this.ctrl_tgh).before(html);
          this.ctrl_el = $(this.ctrl_tgh).prev();
          break;
      }
      this._bindControls();
    },
    
    _bindControls : function() {
      $('a.avanti', this.ctrl_el).bind('click', {oo:this}, function(e) {
        e.data.oo.opts.autoplay = false;
        e.data.oo.opts.verso = 1;
        e.data.oo._draw();
        return false;
      });
      
      $('a.indietro', this.ctrl_el).bind('click', {oo:this}, function(e) {
        e.data.oo.opts.autoplay = false;
        e.data.oo.opts.verso = -1;
        e.data.oo._draw();
        return false;
      });
      
      $('a.dot', this.ctrl_el).bind('click', {oo:this}, function(e) {
        e.data.oo.opts.autoplay = false;
        var num = $(this).attr('href').match(/#\d{1,}/)[0] || 0;
        e.data.oo._draw(num.replace('#',''));
        return false;
      });
    },
    
    _updateControls : function() {
      var idx = this.list.children().index($('.active', this.list));
      switch(this.opts.controls) {
        case 1:
        case 2:
          if (idx==0) {
            $('a.indietro, b.avanti', this.ctrl_el).hide();
            $('b.indietro, a.avanti', this.ctrl_el).show();
          } else if(idx+1 == this.n) {
            $('b.indietro, a.avanti', this.ctrl_el).hide();
            $('a.indietro, b.avanti', this.ctrl_el).show();
          } else {
            $('a.indietro, a.avanti', this.ctrl_el).show();
            $('b.indietro, b.avanti', this.ctrl_el).hide();
          }
          if(this.opts.controls == 2) // agg numero
              $('.svNum', this.ctrl_el).html(idx+1);
          break;
        case 3:
          $('.dot', this.ctrl_el).removeClass('active').eq(idx).addClass('active');
      }
      
    },
    
    _bindKeys : function() {
      document.onkeydown = function(e){
        keycode = (e == null) ? event.keyCode : e.which; // if ie : mozilla
        switch(keycode) {
          case 190: // right
          case 39:
            this.opts.autoplay = false;
            this.opts.verso = 1;
            this._draw();
            break;
          case 188: // left
          case 37:
            this.opts.autoplay = false;
            this.opts.verso = -1;
            this._draw();
            break;
        }
      };
    },
    
    // Helper functions
    _setActive : function($el) {
      // rimuovo la classe e pulisco lo style
      $('.active', this.list).removeClass('active').removeAttr('style');
      $el.addClass('active');
    }
    
  });
  
  $svc.extend({
    
    opts: function(d) {
      return $.extend(opts, d || {});
    }
    
  });
  
})(jQuery);