/**
* @author Ryan Johnson <http://saucytiger.com/>
* @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
* @package LivePipe UI
* @license MIT
* @url http://livepipe.net/control/tabs
* @require prototype.js, livepipe.js
*/
Object.Event = {
  extend: function(object){
    object._objectEventSetup = function(event_name){
      this._observers = this._observers || {};
      this._observers[event_name] = this._observers[event_name] || [];
    };
    object.observe = function(event_name,observer){
      if(typeof(event_name) == 'string' && typeof(observer) != 'undefined'){
        this._objectEventSetup(event_name);
        if(!this._observers[event_name].include(observer))
          this._observers[event_name].push(observer);
      }else
        for(var e in event_name)
          this.observe(e,event_name[e]);
    };
    object.stopObserving = function(event_name,observer){
      this._objectEventSetup(event_name);
      if(event_name && observer)
        this._observers[event_name] = this._observers[event_name].without(observer);
      else if(event_name)
        this._observers[event_name] = [];
      else
        this._observers = {};
    };
    object.observeOnce = function(event_name,outer_observer){
      var inner_observer = function(){
        outer_observer.apply(this,arguments);
        this.stopObserving(event_name,inner_observer);
      }.bind(this);
      this._objectEventSetup(event_name);
      this._observers[event_name].push(inner_observer);
    };
    object.notify = function(event_name){
      this._objectEventSetup(event_name);
      var collected_return_values = [];
      var args = $A(arguments).slice(1);
      try{
        for(var i = 0; i < this._observers[event_name].length; ++i)
          collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
      }catch(e){
        if(e == $break)
          return false;
        else
          throw e;
      }
      return collected_return_values;
    };
    if(object.prototype){
      object.prototype._objectEventSetup = object._objectEventSetup;
      object.prototype.observe = object.observe;
      object.prototype.stopObserving = object.stopObserving;
      object.prototype.observeOnce = object.observeOnce;
      object.prototype.notify = function(event_name){
        if(object.notify){
          var args = $A(arguments).slice(1);
          args.unshift(this);
          args.unshift(event_name);
          object.notify.apply(object,args);
        }
        this._objectEventSetup(event_name);
        var args = $A(arguments).slice(1);
        var collected_return_values = [];
        try{
          if(this.options && this.options[event_name] && typeof(this.options[event_name]) == 'function')
            collected_return_values.push(this.options[event_name].apply(this,args) || null);
          for(var i = 0; i < this._observers[event_name].length; ++i)
            collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
        }catch(e){
          if(e == $break)
            return false;
          else
            throw e;
        }
        return collected_return_values;
      };
    }
  }
};

if(typeof(Prototype) == "undefined")
  throw "Control.Tabs requires Prototype to be loaded.";
if(typeof(Object.Event) == "undefined")
  throw "Control.Tabs requires Object.Event to be loaded.";
if (!Control) var Control = { };
Control.Tabs = Class.create({
  initialize: function(tab_list_container,options){
    if(!$(tab_list_container))
      throw "Control.Tabs could not find the element: " + tab_list_container;
    this.activeContainer = false;
    this.activeLink = false;
    this.containers = $H({});
    this.links = [];
    Control.Tabs.instances.push(this);
    this.options = {
      beforeChange: Prototype.emptyFunction,
      afterChange: Prototype.emptyFunction,
      hover: false,
      linkSelector: 'li a',
      setClassOnContainer: false,
      activeClassName: 'active',
      defaultTab: 'first',
      autoLinkExternal: true,
      targetRegExp: /(#|\%23)(.+)$/,
      showFunction: Element.show,
      hideFunction: Element.hide
    };
    Object.extend(this.options,options || {});
    (typeof(this.options.linkSelector == 'string')
      ? $(tab_list_container).select(this.options.linkSelector)
      : this.options.linkSelector($(tab_list_container))
    ).findAll(function(link){
      return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(/.*(#.*)/, "$1"));
    }).each(function(link){
      this.addTab(link);
    }.bind(this));
    this.containers.values().each(Element.hide);
    if(this.options.defaultTab == 'first')
      this.setActiveTab(this.links.first());
    else if(this.options.defaultTab == 'last')
      this.setActiveTab(this.links.last());
    else
      this.setActiveTab(this.options.defaultTab);
    var targets = this.options.targetRegExp.exec(window.location);
    if(targets && targets[2]){
      targets[2].split(',').each(function(target){
        this.setActiveTab(this.links.find(function(link){
          return link.key == target;
        }));
      }.bind(this));
    }
    if(this.options.autoLinkExternal){
      $A(document.getElementsByTagName('a')).each(function(a){
        if(!this.links.include(a)){
          var clean_href = a.href.replace(window.location.href.split('#')[0],'');
          if(clean_href.substring(0,1) == '#'){
            if(this.containers.keys().include(clean_href.substring(1))){
              $(a).observe('click',function(event,clean_href){
                this.setActiveTab(clean_href.substring(1));
              }.bindAsEventListener(this,clean_href));
            }
          }
        }
      }.bind(this));
    }
  },
  addTab: function(link){
    this.links.push(link);
    link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('/').last().replace(/#/,'');
    var container = $(link.key);
    if(!container)
      throw "Control.Tabs: #" + link.key + " was not found on the page."
    this.containers.set(link.key,container);
    link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
      if(window.event)
        Event.stop(window.event);
      this.setActiveTab(link);
      return false;
    }.bind(this,link);
  },
  setActiveTab: function(link){
    if(!link && typeof(link) == 'undefined')
      return;
    if(typeof(link) == 'string'){
      this.setActiveTab(this.links.find(function(_link){
        return _link.key == link;
      }));
    }else if(typeof(link) == 'number'){
      this.setActiveTab(this.links[link]);
    }else{
      if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false)
        return;
      if(this.activeContainer)
        this.options.hideFunction(this.activeContainer);
      this.links.each(function(item){
        (this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
      }.bind(this));
      (this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
      this.activeContainer = this.containers.get(link.key);
      this.activeLink = link;
      this.options.showFunction(this.containers.get(link.key));
      this.notify('afterChange',this.containers.get(link.key));
    }
  },
  next: function(){
    this.links.each(function(link,i){
      if(this.activeLink == link && this.links[i + 1]){
        this.setActiveTab(this.links[i + 1]);
        throw $break;
      }
    }.bind(this));
  },
  previous: function(){
    this.links.each(function(link,i){
      if(this.activeLink == link && this.links[i - 1]){
        this.setActiveTab(this.links[i - 1]);
        throw $break;
      }
    }.bind(this));
  },
  first: function(){
    this.setActiveTab(this.links.first());
  },
  last: function(){
    this.setActiveTab(this.links.last());
  }
});
Object.extend(Control.Tabs,{
  instances: [],
  findByTabId: function(id){
    return Control.Tabs.instances.find(function(tab){
      return tab.links.find(function(link){
        return link.key == id;
      });
    });
  }
});
Object.Event.extend(Control.Tabs);
