/**
 *  Written for Repka.tv by Dmitry Khavilo
 *  Requires: jQuery 1.3.x and black magic
 *  Copyright 2009 Dmitry Khavilo
**/

function Animator(element)
{
  var options;
  this.animations = {};
  
  try
  {
    options = eval($(element).attr('animate'));
  } catch(e) {}
  if ( options instanceof Array )
  {
    if ( !(options[0] instanceof Array) )
      options = [options];
    
    for (var p = 0; p < options.length; p++)
    {
      this.animations[options[p][0]] = options[p].slice(1); 
    }
  }
  delete options;
  
  this.getAnimation = function(placeholderName)
  {
    if ( placeholderName in this.animations )
      return this.createAnimation(this.animations[placeholderName]);
    else
      return this.createAnimation();
  };
  
  this.createAnimation = function(options)
  {
    if (options)
      switch(options[0])
      {
        case 'slide':
          return new slideAnimation(options);
        default:
          return new DefaultAnimation(options);
      }
    else
      return new DefaultAnimation(options);
  };
}

function DefaultAnimation(options)
{
  this.options = options;
  this.placeholder = null;
  this.content = null;

  this.run = function(placeholder, newContent)
  {
    this.placeholder = this.content = placeholder;
    
    this.placeholder.data('animation', this);
    this.animate(newContent);
    return this;
  };
  
  this.animate = function(newContent)
  {
    this.placeholder.empty().html(newContent);
    this.stop();
    return this;
  };
  
  this.stop = function()
  {
    this.placeholder.removeData('animation');
    return this;
  };
  
  this.updateContent = function (content)
  {
    this.content.get(0).innerHTML = content;
    return this;
  };
}

function slideAnimation(options)
{
  DefaultAnimation.call(this, options);
  
  this.animate = function(newContent)
  {
    var width = this.placeholder.width();
    var height = this.placeholder.height();
    var dir = this.options[1];
    var wrapper = this.placeholder.wrapInner('<div />').children().eq(0).css({overflow: 'hidden', 'width': width, 'height': height, position: 'relative'});
    var oldContent = wrapper.wrapInner('<div />').children().eq(0).css({position: 'absolute', left: 0, 'width': width});
    this.content = $('<div/>').css({'width': width, 'height': height, position: 'absolute', backgroundColor: this.placeholder.css('backgroundColor'), left: dir > 0 ? width : -width}).appendTo(wrapper).html(newContent);
    
    if ( Math.abs(dir) == 1)
      oldContent.animate({left: dir > 0 ? -width : width});
    this.content.animate({left: 0}).queue(function(anim){ return function() {$(this).dequeue();anim.stop();}; }(this));
    
    return this;
  };
  
  this.stop = function()
  {
    this.placeholder.removeData('animation');
    var content = this.content.children().appendTo(this.placeholder);
    this.placeholder.children().not(content).remove();
    return this;
  };

}

(function($){
  
  $.fn.tabify = function()
  { 
    return this.each(function(bI)
    {
      var $block = $(this);
  
      $block.setData = function(tabData, animator)
      {
        for ( var holderName in tabData )
        {
          var placeHolder = $(holderName, $block);
          placeHolder.unbind();
          if (tabData[holderName].content != undefined)
          {
            if (animator)
            {
              if ( placeHolder.data('animation') ) placeHolder.data('animation').stop();
              animator.getAnimation(holderName).run(placeHolder, tabData[holderName].content);
            }
            else if ( placeHolder.data('animation') )
            {
              placeHolder.data('animation').updateContent(tabData[holderName].content);
            }
            else
              placeHolder.empty().html(tabData[holderName].content);
          }
          if (tabData[holderName].events != undefined)
          {
            var events = tabData[holderName].events; 
            for ( var eventTarget in events)
              for ( var eventName in events[eventTarget])
              {
                var callBack = function (fn)
                {
                  return function(e) {
                    this.block = $block;
                    return fn.call(this, e);
                  };
                } (events[eventTarget][eventName]);
                if (eventTarget != '')
                  $(eventTarget, placeHolder).bind(eventName, callBack);
                else
                  placeHolder.bind(eventName, callBack);
              }
            delete events;
          }
        }
      };
  
      $block.loadContent = function(object, e)
      {
        var $this = $(object);
        var target = $this.attr('url') || $this.attr('target');
        if ( !$this.attr('url') || $CACHE.isset(target) )
        {
          if ($block.request) $block.request.hidden = true;
          $block.setData($CACHE.get(target), new Animator($this));
        }
        else
        {
          $block.setData($CACHE.get('_DEFAULT_'), new Animator($this));
          if ($block.request) $block.request.abort();
          $block.request = $.get(target, null, function(data){
            var hidden = $block.request ? $block.request.hidden || false : false;
            delete $block.request;
            $CACHE.set(target, data);
            if (!hidden) $block.setData($CACHE.get(target));
          }, 'json');
        }
      };
  
      $('.magic-tabsHolder', $block).each(function()
      {
        var selected = 0; 
        var $tabs = [];
        var cycler = $(this).hasClass('.magic-cycler');
        
        /** caching _DEFAULT_ content **/
        var block_content = {};
        var block_parts = $('.magic-default', $block);
        for ( var i = 0; i < block_parts.length; i++ )
          block_content[block_parts.eq(i).attr('target')] = { content: block_parts.eq(i).html() };
        if (i)
          $CACHE.merge('_DEFAULT_', block_content, true);
        block_parts.remove();
        delete block_content, block_parts;
        
        
        /** tabs initialization **/
        $('.magic-tab', $block).each(function(tabIndex){
  
          var $tab = $(this);
          $tabs.push($tab);

          var url = $tab.attr('url');
          
          var target = $tab.target = url || $tab.attr('target');
          
  
          if ( $tab.hasClass('magic-tab-selected'))
            selected = tabIndex;
  
          /** caching default content **/
          var block_content = {};
          var block_parts = $($tab.attr('target'), $block);
          for ( var i = 0; i < block_parts.length; i++ )
            block_content[block_parts.eq(i).attr('target')] = { content: block_parts.eq(i).html() };
          if (i)
            $CACHE.merge(target, block_content, true);
          block_parts.not(':visible').remove();
          delete block_content, block_parts;

          if ( !cycler )
          {
            $tab.click(function(e)
            {
              if (selected != tabIndex)
              {
                $tab.addClass('magic-tab-selected');
                $tabs[selected].removeClass('magic-tab-selected');
                selected = tabIndex;
                $block.find('.magic-placeholder').trigger('unload_tab');
                $block.loadContent($tab);
              }
              return false;
            });
          }
          else
          {
            $tab.click(function(e)
            {
              if (selected == tabIndex)
              {
                selected = tabIndex + 1;
                if ( selected == $tabs.length ) selected = 0; 
                $tab.removeClass('magic-tab-selected');
                if ($tab.hasClass('regenerate')) 
                {
                  $tab.removeClass('regenerate');
                  $CACHE.merge(target, {'.magic-contentHolder':{ content: $('.magic-contentHolder', $block).html() }});
                };
                $tabs[selected].addClass('magic-tab-selected');
                $block.find('.magic-placeholder').trigger('unload_tab');
                $block.loadContent($tabs[selected]);
              }
              return false;
            });
          }
        });
  
        if ($tabs.length)
        {
          $tabs[selected].addClass('magic-tab-selected');
          $block.setData($CACHE.get($tabs[selected].target));
        }
      });
      
    });
  };
  
  $(document).ready(function(){$('.magic-block').tabify();});
  
})(jQuery);
