var TabManager = Class.create();

TabManager.prototype = {
		
		initialize: function(baseId, options) {
		
			this.options = {
	
				baseName: 'tabs',
							
				triggers: true,
				triggerWrapper: 'tabs-triggers',
				triggerBaseNode: '',
				triggerActivator: 'a',
				parentHasOnClass: true,
				
				buttons: false,
				buttonWrapper: 'button-wrapper',
				buttonForward: 'button-forward',
				buttonBack: 'button-backward',
				buttonRotate: 'button-rotate',
				buttonStopRotate: 'button-stoprotate',
				
				slides: '',
				useSlideClass: false,
				slideBaseWrapper: 'div',
				
				firstIndex: 1,
				action: 'click',
				onState: 'on',
				offState: 'off',
				hoverState: 'hover',
				noFollow: false,
				
				autoPlayDelay: 2000,
				
				mode: 'firstOn'
			}
			
			// check to see if the base tab wrapper is the first property passed in the constructor.  If not, make pass the options property to the element property //
			if (typeof baseId == 'string') 
				options.baseName = baseId;
			else {
				options = baseId;
			}
		
			Object.extend(this.options, options || {});
			
			this.currentSlide = this.options.firstIndex ? this.options.firstIndex - 1 : 0;
		
			// set up the trigger items which change the slides  //
			if(this.options.triggers) {
				var triggers = $(this.options.triggerWrapper).getElementsByTagName(this.options.triggerActivator);
				this.triggers = $A(triggers);
				this.totalSlides = this.setTriggers(this.triggers);
			} 
			
			/* set up the data that switches when the trigger is clicked 
			 if we pass in something thats not an array, make it one.  If we don't
			 pass in the slide wrapper, use the base id */
			
			if (this.options.slides != '') 
				this.slides = (typeof this.options.slides == 'object') ? this.options.slides : [this.options.slides]
			else 
				this.slides = [this.options.baseName]
			
			this.totalSlides = this.setslides(this.slides);
			
			// call before start //
			if (typeof this.options.beforeStart == 'function')
				this.options.beforeStart.apply(this, arguments);
			
			if(this.options.buttons) {
				this.setButtons();
			}
		
			// start the TabManager on the chosen mode //
			this.start[this.options.mode].bind(this)(); 
		
		},
		
		start: {
			
			contained : function () {
				this.currentSlide = 0;
			},
			
			firstOn : function () {
				this.showFirst()
			},
			
			autoPlay : function () {
				this.options.autoPlay = true,
				this.showFirst();
				this.setAutoPlay();
			},
			
			autoPlayOnce: function () {
				this.autoPlayThru = 0;
				this.options.autoPlayOnceThru = true,
				this.showFirst();
				this.setAutoPlay();
			}
		
		},
		
		
		
		setTriggers: function(els) {  // takes array of elements
			for(x=0; x<els.length; x++) {
				
				els[x].id = this.options.baseName + "-tr-" + x;
			
				// hide the initial state that is on for javascriptless browsers
				$(this.getBase(els[x].id)).removeClassName(this.options.onState);				
				
				if (this.options.mode == 'contained') {
					Event.observe(els[x], 'mouseover', this.show.bind(this) );
				}
				
				else {
					Event.observe(els[x], this.options.action, this.swap.bind(this) );
				}
				
				if ( (this.options.action != 'click') && (this.options.noFollow) )
						Event.observe(els[x], 'click', function(e) { Event.stop(e) } )
			}
			
			return els.length;
		},
		
		
		setslides: function(ids) { // takes an array of ids or a single id //
		
			this.slides.each(function(set, nodeCounter) {
		
				// if we want to use a class to define the slides //
				if (this.options.useSlideClass) 
					slideSet = $A( $(set).getElementsByClassName(this.options.useSlideClass, this.options.slideBaseWrapper) )
				else 
					slideSet = $A( $(set).getElementsByTagName(this.options.slideBaseWrapper) )
				
				
				slideSet.each(function(subEl, counter) {
					
						$(subEl).id = this.options.baseName + "-sl-" + nodeCounter + "-" + counter;
						$(subEl).style.display = 'none'; // hide em all and set up the initial "on" so it wont goof up the page if JS is off //
						
				}.bind(this) );
				
				
			
			}.bind(this) );
			
			
			
			return slideSet.length;

		},
	
		
		getIndex: function(node, el) { // takes an element //
					
			if (el == null) {
				el = node;
				node = this.triggers;
			}
				
			return node.indexOf(el);
		},
		
		swap: function(e) { 
	
			var next = this.getIndex(this.triggers, Event.element(e));
			var current = this.currentSlide;
			
			if (current != next) {
				this.toggle(current, next);
			}
			
			// set the current Index //
			this.currentSlide = next;
			// dont go to the linked page and stop default action //
			if(e) Event.stop(e);
			// if we are rotating, override it and shut it off //
			this.stopAutoPlay();	
			
			
		},
		
		smartSwap: function(e, direction) {
			
			// we will take the total number of els and auto go through them.
	
			var current = this.currentSlide;
		
			switch (direction) {
				case 'forward' :
					next = (current >= this.totalSlides-1) ? 0 : current + 1;
					this.stopAutoPlay();
					break;
				case 'backward' :
					next = (current == 0) ? this.totalSlides-1 : current - 1;
					this.stopAutoPlay();
					break;
				default:
					next = (current >= this.totalSlides-1) ? 0 : current + 1;
					break;
			}
				
			this.toggle(current, next);
			
			// set to the next slide so we know where we are //
			this.currentSlide = next;
	
			// if we have the autoPlayFlag on, cycle through the elements only once //
			if (this.options.mode == "autoPlayOnce" ) {
				if (this.autoPlayThru < this.totalSlides - 1) 
					this.autoPlayThru++;
				else { 
					this.stopAutoPlay();	 
				}		
			}
				
			// dont go to the linked page if onclick //
			if(e) Event.stop(e);
		
		},
		
		getBase: function(id) { // takes an id, returns element //
		
			// the getBase returns the node which carries the on class for the trigger //
			
			// if parentHasOnClass is true, the immediate parent is returned //
			if (this.options.parentHasOnClass) {
				return $(id).parentNode;
			}
			
			else {
				
				// otherwise, get the node that will hold the on class //
				if (this.options.triggerBaseNode) {
					var t = $(id).tagName
					var parent = $(id);
					
					while( t != this.options.triggerBaseNode.toUpperCase()) {
						parent = parent.parentNode
						t = parent.tagName
					}
					return $(parent);
				}
				
				// otherwise, the trigger carries the on class //
				else {
					return $(id);
				}
			}
			
		},
		
	
		toggle : function(current, next) { // takes indexes for the next and current slides //
			
			this.show(next);
			this.hide(current);
			
		},
		
		show : function(e, index) { // takes an index //
			
			// change the behavior of index depending on the mode you are in //
			if (this.options.mode == 'contained') {
				index = this.getIndex(this.triggers, Event.element(e));
			}
			else {
				index = e;
			}
			
			// call before showing //
			if (typeof this.options.beforeShow == 'function')
				this.options.beforeShow.apply(this, arguments);
					
			
			if (this.options.triggers) { 
				parentNode = this.getBase(this.triggers[index].id)
				parentNode.addClassName(this.options.onState);
			}
			
			this.slides.each( function(set, counter)  {
					// turn on vertical constraining for the wrapper -- you must have a height set for this to work //
					if (this.options.verticalConstrain) this.verticalConstrain(set, index);
					slideId = this.options.baseName + "-sl-" + counter + "-" + index;
					this.flipFlop( $(slideId) );
			}.bind(this) )
	
			// call after showing //
			if (typeof this.options.afterShow == 'function')
				this.options.afterShow.apply(this, arguments);
	
		
		},
		
		hide : function(e, index) { // takes an index //
		
			// change the behavior of index depending on the mode you are in //
			if (this.options.mode == 'contained') {
				index = this.getIndex(this.triggers, Event.element(e));
			}
			else {
				index = e;
			}
			
			if (this.options.triggers) { 
				parentNode = this.getBase(this.triggers[index].id)
				$(parentNode).removeClassName(this.options.onState);
			}
			
			this.slides.each( function(set, counter)  {
					slideId = this.options.baseName + "-sl-" + counter + "-" + index;
					this.flipFlop( $(slideId) );
			}.bind(this) )
			
		},
		
		flipFlop: function(el) { // takes an element

			el.style.display = ( (el.style.display) == 'block' ) ? 'none' : 'block';
			
		},
		
		setAutoPlay: function(e) {
			
			if (!this._TabsPlayer) {
				this._TabsPlayer = setInterval(this.smartSwap.bind(this), this.options.autoPlayDelay);
			}
			
			if(e) { 
				Event.stop(e);
				this.options.autoPlayOnceThru = false;
			}
		
		},
		
		stopAutoPlay: function(e) {
			
			clearInterval(this._TabsPlayer);
			this._TabsPlayer = null;
			this.options.autoPlayOnceThru = false;
			if(e) Event.stop(e);
		
		},
		
		
		showFirst : function() {
			this.show(this.currentSlide);
		}

}

TabManager.AddOns = {
	
		setButtons: function() {
		
			if(this.options.buttonForward) {
				var buttonForward = $(this.options.buttonWrapper).getElementsByClassName(this.options.buttonForward);
				Event.observe( $(buttonForward[0]), "click", this.smartSwap.bindAsEventListener(this, 'forward') );
			}
			
			if(this.options.buttonBack) {
				var buttonBack = $(this.options.buttonWrapper).getElementsByClassName(this.options.buttonBack);
				Event.observe( $(buttonBack[0]), "click", this.smartSwap.bindAsEventListener(this, 'backward') );
			}
			
			if(this.options.buttonRotate) {
				var buttonRotate = $(this.options.buttonWrapper).getElementsByClassName(this.options.buttonRotate);
				Event.observe( $(buttonRotate[0]), "click", this.setAutoPlay.bindAsEventListener(this) );
			}
			
			if(this.options.buttonStopRotate) {
				var buttonStopRotate = $(this.options.buttonWrapper).getElementsByClassName(this.options.buttonStopRotate);
				Event.observe( $(buttonStopRotate[0]), "click", this.stopAutoPlay.bindAsEventListener(this) );
				
			}
			
		},
		
		verticalConstrain: function(set, index) {
			
			var slideOffset = 12;
			
			var baseHeight = $(set).getHeight();
			var totalBasePadding = parseInt($(this.options.baseName).getStyle('padding-top')) + parseInt($(set).getStyle('padding-bottom'));
		
			baseHeight = baseHeight - totalBasePadding;
			
			var parentNode = this.getBase(this.triggers[index].id)
			var triggerTop = parentNode.offsetTop;
			
			var slideId = this.options.baseName + "-sl-" + 0 + "-" + index;
			var slideHeight = $(slideId).getHeight();
			var slideBasePadding = parseInt($(slideId).getStyle('padding-top')) + parseInt($(slideId).getStyle('padding-bottom'));
				
			var useOffset = false;
			var useScroll = true;
			
			var verticalOrientation = ((triggerTop + slideHeight) < baseHeight) ? 'top' : 'bottom';
			
			switch(verticalOrientation) {
				case 'top' :
					useOffset = true
				break
							
				case 'bottom': 
					useOffset = false //set this true to use an offset on the bottom ones //
				break
			}
			
			
			if (useOffset) {
				var verticalPosition = ((triggerTop - slideOffset) > 0) ? triggerTop - slideOffset : 0;
			}
			else {
				var verticalPosition = 0 + slideOffset;
			}
			
			if (useScroll) {
				if (slideHeight > baseHeight) {
					$(slideId).style.height = baseHeight - slideBasePadding + 'px';
					$(slideId).style.overflow = 'auto';
					
				}
			}
					
			if (verticalOrientation == 'top') {
				$(slideId).style.top = verticalPosition + 'px';
				$(slideId).style.bottom = 'auto';
			}
			else {
				$(slideId).style.top = 'auto';
				$(slideId).style.bottom = verticalPosition + 'px';
			}
					
		}
				
		
	}
	
// add the add-on methods to the main tab prototype //
Object.extend(TabManager.prototype, TabManager.AddOns)

var infoMenu = new TabManager( { 
	baseName: "tabs",
	triggerWrapper: "message-nav",
	slides: ["message-info", "message-more"],
	action: "mouseover",
	mode: 'autoPlayOnce',
	buttons: false,
	autoPlayDelay: 5000
} );

