/**
 * tools.tabs 1.0.4 - Tabs done right.
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/tabs.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch  : November 2008
 * Date: ${date}
 * Revision: ${revision} 
 */  
(function($) {
    
  // static constructs
  $.tools = $.tools || {};
  
  $.tools.tabs = {
    version: '1.0.4',
    
    conf: {
      tabs: 'a',
      current: 'current',
      onBeforeClick: null,
      onClick: null, 
      effect: 'default',
      initialIndex: 0,      
      event: 'click',
      api:false,
      rotate: false
    },
    
    addEffect: function(name, fn) {
      effects[name] = fn;
    }
  };    
  
  
  var effects = {
    
    // simple "toggle" effect
    'default': function(i, done) { 
      this.getPanes().hide().eq(i).show();
      done.call();
    }, 
    
    /*
      configuration:
        - fadeOutSpeed (positive value does "crossfading")
        - fadeInSpeed
    */
    fade: function(i, done) {
      var conf = this.getConf(), 
         speed = conf.fadeOutSpeed,
         panes = this.getPanes();
      
      if (speed) {
        panes.fadeOut(speed); 
      } else {
        panes.hide(); 
      }

      panes.eq(i).fadeIn(conf.fadeInSpeed, done); 
    },
    
    // for basic accordions
    slide: function(i, done) {      
      this.getPanes().slideUp(200);
      this.getPanes().eq(i).slideDown(400, done);      
    }, 

    // simple AJAX effect
    ajax: function(i, done)  {      
      this.getPanes().eq(0).load(this.getTabs().eq(i).attr("href"), done);  
    }
    
  };    
  
  var w;
  
  // this is how you add effects
  $.tools.tabs.addEffect("horizontal", function(i, done) {
  
    // store original width of a pane into memory
    if (!w) { w = this.getPanes().eq(0).width(); }
    
    // set current pane's width to zero
    this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); });
    
    // grow opened pane to it's original width
    this.getPanes().eq(i).animate({width: w}, function() { 
      $(this).show();
      done.call();
    });
    
  }); 
   

  function Tabs(tabs, panes, conf) { 
    
    var self = this, $self = $(this), current;

    // bind all callbacks from configuration
    $.each(conf, function(name, fn) {
      if ($.isFunction(fn)) { $self.bind(name, fn); }
    });
    
    
    // public methods
    $.extend(this, {        
      click: function(i, e) {
        
        var pane = self.getCurrentPane();       
        var tab = tabs.eq(i);                        
        
        if (typeof i == 'string' && i.replace("#", "")) {
          tab = tabs.filter("[href$=" + i.replace("#", "") + "]");
          i = Math.max(tabs.index(tab), 0);
        }
                
        if (conf.rotate) {
          var last = tabs.length -1; 
          if (i < 0) { return self.click(last, e); }
          if (i > last) { return self.click(0, e); }            
        }
        
        if (!tab.length) { 
          if (current >= 0) { return self; }
          i = conf.initialIndex;
          tab = tabs.eq(i);
        }       
        
        // current tab is being clicked
        if (i === current) { return self; }
        
        // possibility to cancel click action       
        e = e || $.Event();
        e.type = "onBeforeClick";
        $self.trigger(e, [i]);        
        if (e.isDefaultPrevented()) { return; }
        
        // call the effect
        effects[conf.effect].call(self, i, function() {

          // onClick callback
          e.type = "onClick";
          $self.trigger(e, [i]);          
        });     
        
        // onStart
        e.type = "onStart";
        $self.trigger(e, [i]);        
        if (e.isDefaultPrevented()) { return; } 
        
        // default behaviour
        current = i;
        tabs.removeClass(conf.current); 
        tab.addClass(conf.current);       
        
        return self;
      },
      
      getConf: function() {
        return conf;  
      },

      getTabs: function() {
        return tabs;  
      },
      
      getPanes: function() {
        return panes; 
      },
      
      getCurrentPane: function() {
        return panes.eq(current); 
      },
      
      getCurrentTab: function() {
        return tabs.eq(current);  
      },
      
      getIndex: function() {
        return current; 
      }, 
      
      next: function() {
        return self.click(current + 1);
      },
      
      prev: function() {
        return self.click(current - 1); 
      }, 
      
      bind: function(name, fn) {
        $self.bind(name, fn);
        return self;  
      },  
      
      onBeforeClick: function(fn) {
        return this.bind("onBeforeClick", fn);
      },
      
      onClick: function(fn) {
        return this.bind("onClick", fn);
      },
      
      unbind: function(name) {
        $self.unbind(name);
        return self;  
      }     
    
    });
    
    
    // setup click actions for each tab
    tabs.each(function(i) { 
      $(this).bind(conf.event, function(e) {
        self.click(i, e);
        return false;
      });     
    });

    // if no pane is visible --> click on the first tab
    if (location.hash) {
      self.click(location.hash);
    } else {
      if (conf.initialIndex === 0 || conf.initialIndex > 0) {
        self.click(conf.initialIndex);
      }
    }   
    
    // cross tab anchor link
    panes.find("a[href^=#]").click(function(e) {
      self.click($(this).attr("href"), e);    
    }); 
  }
  
  
  // jQuery plugin implementation
  $.fn.tabs = function(query, conf) {
    
    // return existing instance
    var el = this.eq(typeof conf == 'number' ? conf : 0).data("tabs");
    if (el) { return el; }

    if ($.isFunction(conf)) {
      conf = {onBeforeClick: conf};
    }
    
    // setup options
    var globals = $.extend({}, $.tools.tabs.conf), len = this.length;
    conf = $.extend(globals, conf);   

    
    // install tabs for each items in jQuery    
    this.each(function(i) {       
      var root = $(this); 
      
      // find tabs
      var els = root.find(conf.tabs);
      
      if (!els.length) {
        els = root.children();  
      }
      
      // find panes
      var panes = query.jquery ? query : root.children(query);
      
      if (!panes.length) {
        panes = len == 1 ? $(query) : root.parent().find(query);
      }     
      
      el = new Tabs(els, panes, conf);
      root.data("tabs", el);
      
    });   
    
    return conf.api ? el: this;   
  };    
    
}) (jQuery); 



