/*
               Notes:
                - you don't have to specify the classes for mouseover/out
                - you don't have to specify a click selector; it'll just
                  use the tab DOM elements if you don't give it the click
                        selector
                - the click selector is NOT a subselector of the tabs; be sure
                  to specify a full css selector for these
                - smooth: is off by default; adds some nice transitional effects
                - cookieName: will store the users's last selected tab in a cookie
                  and restore this tab when they next visit
                       
Arguments:
       options - optional, an object containing options.

Options:
                       selectedClass - the class for the tab when it is selected
                       deselectedClass - the class for the tab when it isn't selected
                       mouseoverClass - the class for the tab when the user mouses over
                       rearrangeDOM - (boolean) arranges the tabs and sections in the dom to be in the same order as they are in the class; defaults to true.
                       tabs - (array) an array of DOM elements for the tabs (these get the above classes added to them when the user interacts with the interface); can also be a <$$> selector (string).
                       clickers - (optional, array) an array of DOM elements for the clickers; if your tab contains a child DOM element that the user clicks - not the whole tab but an element within it - to switch the content, pass in an array of them here. If you don't pass these in, the array of tabs is used instead (the default). Can also be a <$$> selector (string).
                       sections - (array) an array of DOM elements for the sections (these change when the clickers are clicked); can also be a <$$> selector (string).
                       initPanel - the panel to show on init; 0 is default (optional)
                       smooth - use opacity effect to smooth transitions; false is default (optional)
                       smoothSize - smoothly resize the sections from one section to the other; false is default
                       cookieName - if defined, the browser will remember their previous selection
                                               using a cookie (optional)
                       cookieDays - how many days to remember this? default is 999, but it's
                                               ignored if cookieName isn't set (optional)
                       effectOptions - the options to pass on to the transition effect if the "smooth" option is set to true; defaults to {duration: 500}
                       onBackground - callback executed when a section is hidden; passed three arguments: the index of the section, the section, and the tab
                       onActive - callback executed when a section is shown; passed three arguments: the index of the section, the section, and the tab
                       onActiveAfterFx - callback executed when a section is shown but after the effects have completed (so it's visible to the user); passed three arguments: the index of the section, the section, and the tab
       */

var TabSwapper = new Class({
       options: {
               selectedClass: 'tabSelected',
               mouseoverClass: 'tabover',
               deselectedClass: '',
               rearrangeDOM: false, //IE 6 chokes on this
               smooth: true,
               smoothSize: false,
               maxSize: null,
               effectOptions: { duration: 500 },
               cookieName: '',
               cookieDays: 1,
			   initPanel: 0,
               onActive: Class.empty,
               onActiveAfterFx: Class.empty,
               onBackground: Class.empty
       },
       initialize: function(options){
               this.tabs = [];
               this.sections = [];
               this.clickers = [];
               this.sectionFx = [];
               options = this.compatability(options);
               this.setOptions(options);
               this.setup();

               if(this.options.cookieName && this.recall()) this.swap(this.recall().toInt());
               else this.swap(this.options.initPanel);
       },
       compatability: function(options){
               if(options.tabSelector){
                       options.tabs = $$(options.tabSelector);
                       options.sections = $$(options.sectionSelector);
                       options.clickers = $$(options.clickSelector);
               }
               return options;
       },
       setup: function(){
               var opt = this.options;
               sections = $$(opt.sections);
               tabs = $$(opt.tabs);
               clickers = $$(opt.clickers);
               tabs.each(function(tab, index){
                       this.addTab(tab, sections[index], clickers[index], index);
               }, this);
       },
/*      Property; addTab
               Adds a tab to the interface.
               
               Arguments:
               tab - (DOM element) the tab; (see Options)
               clicker - (DOM element) the clicker
               section - (DOM element) the section
               index - (integer, optional) where to insert this tab; defaults to the last place (i.e. push)
       */
       addTab: function(tab, section, clicker, index){
               tab = $(tab); clicker = $(clicker); section = $(section);
               //if the tab is already in the interface, just move it
               if(this.tabs.indexOf(tab) >= 0 && tab.getProperty('tabbered')
                        && this.tabs.indexOf(tab) != index && this.options.rearrangeDOM) {
                       this.moveTab(this.tabs.indexOf(tab), index);
                       return;
               }
               //if the index isn't specified, put the tab at the end
               if(!$defined(index)) index = this.tabs.length;
               //if this isn't the first item, and there's a tab
               //already in the interface at the index 1 less than this
               //insert this after that one
               if(index > 0 && this.tabs[index-1] && this.options.rearrangeDOM) {
                       tab.injectAfter(this.tabs[index-1]);
                       section.injectAfter(this.sections[index-1]);
               }
               this.tabs.splice(index, 0, tab);
               this.sections.splice(index, 0, section);
               clicker = clicker || tab;
               this.clickers.splice(index, 0, clicker);

               tab.addEvent('mouseout',function(){
                       tab.removeClass(this.options.mouseoverClass);
               }.bind(this)).addEvent('mouseover', function(){
                       tab.addClass(this.options.mouseoverClass);
               }.bind(this));

               clicker.addEvent('click', function(){
                       this.swap(this.clickers.indexOf(clicker));
               }.bind(this));

               tab.setProperty('tabbered', true);
               this.hideSection(index);
               return;
       },
/*      Property: removeTab
       Removes a tab from the TabSwapper; does NOT remove the DOM elements for the tab or section from the DOM.

       Arguments:
       index - (integer) the index of the tab to remove.
*/
       removeTab: function(index){
               var now = this.tabs[this.now];
               if(this.now == index){
                       if(index > 0) this.swap(index - 1);
                       else if (index < this.tabs.length) this.swap(index + 1);
               }
               this.sections.splice(index, 1);
               this.tabs.splice(index, 1);
               this.clickers.splice(index, 1);
               this.sectionFx.splice(index, 1);
               this.now = this.tabs.indexOf(now);
       },
/*      Property: moveTab
               Moves a tab's index from one location to another.
               
               Arguments:
               from - (integer) the index of the tab to move
               to - (integer) its new location
       */
       moveTab: function(from, to){
               var tab = this.tabs[from];
               var clicker = this.clickers[from];
               var section = this.sections[from];
               
               var toTab = this.tabs[to];
               var toClicker = this.clickers[to];
               var toSection = this.sections[to];
               
               this.tabs.remove(tab).splice(to, 0, tab);
               this.clickers.remove(clicker).splice(to, 0, clicker);
               this.sections.remove(section).splice(to, 0, section);
               
               tab.injectBefore(toTab);
               clicker.injectBefore(toClicker);
               section.injectBefore(toSection);
       },
/*      Property: swap
               Swaps the view from one tab to another.
               
               Arguments:
               swapIdx - (integer) the index of the tab to show.
       */
       swap: function(swapIdx){
               if (!$chk(this.now)) {
                       this.sections.each(function(sect, idx){
                               if (swapIdx != idx)
                                       this.hideSection(idx)
                       }, this);
               }
               this.showSection(swapIdx);
               this.save(swapIdx);
       },
       save: function(index){
               if(this.options.cookieName)
                       Cookie.set(this.options.cookieName, index, {duration:this.options.cookieDays});
       },
       recall: function(){
               return (this.options.cookieName)?$pick(Cookie.get(this.options.cookieName), false): false;
       },
       hideSection: function(idx) {
               if (this.sections[idx].getStyle('display') != 'none') {
                       this.lastHeight = this.sections[idx].getSize().size.y;
                       this.sections[idx].setStyle('display', 'none');
                       this.tabs[idx].removeClass(this.options.selectedClass).addClass(this.options.deselectedClass);
                       this.fireEvent('onBackground', [idx, this.sections[idx], this.tabs[idx]]);
               }
       },
       showSection: function(idx) {
               var sect = this.sections[idx];
               if (!sect) return this;
               var smoothOk = this.options.smooth; //&& (!window.ie6 || (window.ie6 && sect.fxOpacityOk()));
               if(this.now != idx) {
                       if (!this.sectionFx[idx]) this.sectionFx[idx] = this.sections[idx].effects(this.options.effectOptions);
                       var start = {
                               display:'block',
                               overflow: "hidden"
                       };
                       if (smoothOk) start.opacity = 0;
                       var effect = false;
                       if(smoothOk) {
                               effect = {opacity: 1};
                       } else if (sect.getStyle('opacity') < 1) {
                               this.sectionFx[idx].set({opacity: 1});
                               if (!this.options.smoothSize) this.fireEvent('onActiveAfterFx', [idx, this.sections[idx], this.tabs[idx]]);
                       }
                       if (this.options.smoothSize) {
                               var size = sect.getDimensions().height;
                               if ($chk(this.options.maxSize) && this.options.maxSize < size) size = this.options.maxSize;
                               if (!effect) effect = {};
                               effect.height = size;
                       }
                       if ($chk(this.now)) this.hideSection(this.now);
                       if (this.options.smoothSize && this.lastHeight) start.height = this.lastHeight;
                       sect.setStyles(start);
                       if (effect) {
                               this.sectionFx[idx].start(effect).chain(function(){
                                       this.fireEvent('onActiveAfterFx', [idx, this.sections[idx], this.tabs[idx]]);
                                       sect.setStyle("height", "auto");
                               }.bind(this));
                       }
                       this.now = idx;
                       this.fireEvent('onActive', [idx, this.sections[idx], this.tabs[idx]]);
               }
               this.tabs[idx].addClass(this.options.selectedClass).removeClass(this.options.deselectedClass);
         return this;
       }
});
TabSwapper.implement(new Options);
TabSwapper.implement(new Events);
//legacy namespace
var tabSwapper = TabSwapper;



