/**
* Initialize and manage a semantic tab box.
*
* This code was created by Jeremy Gillick.
* To learn more, read the blog post: http://blog.mozmonkey.com/2007/semantic-tab-box-v20/
*
* The configuration object names and default values:
* 
*	header   : h3     // The header element used for each tab name.
*	vertical : false  // TRUE if the tabs should be oriented vertically.
*	select   : 0      // The tab index to select initially.
*	autosize : true   // Automatically size the box to the content of the tab.
*
* @param {String} id The ID of the tab box div.
* @param {Object} config The configuration object.
*/
function Tabbox(id, config) { 
	this.init(id, config);
}
Tabbox.prototype = {
	
	tabbox : null,
	tabs : [],
	selected : null,
	
	config : {
		header: "h3",
		vertical: false,
		select : -1,
		padding: 0,
		autosize: true
	},
	
	/**
	* Called from the constructor to start initializing the tabbox.
	*/
	init : function(id, config){
		this.id = id;
		this.loadingId = id + 'Loader';
		var obj = this;
		
		/* 
		* Merge configuration with default values
		*/
		if(config){
			var name;
			for(name in config){
				this.config[name] = config[name];
			}
		}
		
		/* 
		* Poll until the tabbox is available
		*/
		
		// Add onload handler
		this.pageLoaded = false;
		if(window.addEventListener){
			window.addEventListener("load", poll, false);
		}
		else if(window.attachEvent){
			window.attachEvent("onload", poll);
		}
		
		function poll(){
			
			if (!obj.attemptCount) {
				obj.attempCount = 1;
			}
			else {
				obj.attemptCount++;
			}
			
			var tabbox = document.getElementById(id);
			
			// Check for nextSibling in heirarchy
			var node = tabbox;
			
			if(node && node.nextSibling){
				obj.tabbox = tabbox;
				obj.formatTabbox();
				
				if (obj.hidden) {
					
					// check if there's a loader to hide
					var loader = document.getElementById(obj.loadingId);
					
					if (loader) {
						var parent = loader.parentNode;
						
						if (parent) {
							parent.removeChild(loader);
						}
					}
					
					// show the tabbox
					obj.tabbox.style.visibility = 'visible';
				}
				return;
			}
			
			if (obj.attemptCount == 1) {
				// continue polling
				setTimeout(poll, 1000); 
			}
			else {
				return;
			}
		}
		
		poll();
	},
	
	/**
	* Add CSS classes and find the important elements of the tab box.
	*/
	formatTabbox : function(){
		var obj = this;
	
		// Add classes
		this.tabbox.className += " tabbox";
		if(this.config.vertical){
			this.tabbox.className += " verticalTabs";
		}
		else{
			this.tabbox.className += " horzTabs";
		}
	
		// Get tabs
		var divs;
		var tabs = this.tabbox.getElementsByTagName(this.config.header);
		for(var i = 0; i < tabs.length; i++){
			// Tab container
			this.tabs[i] = { id: tabs[i].id, header: tabs[i], container: tabs[i].parentNode };
			// Tab content
			divs = this.tabs[i].container.getElementsByTagName("div");
			for(var n = 0; n < divs.length; n++){
				if(divs[n].className.match(/(^|\s)tabContent(\s|$)/)){
					this.tabs[i].id = divs[n].id;
					this.tabs[i].content = divs[n];
					break;
				}
			}
			
		}
		
		// Add event handlers
		var anchor;
		for(var i = 0; i < this.tabs.length; i++){
			anchor = this.tabs[i].container.getElementsByTagName("a");
			if(anchor.length > 0){
				anchor = anchor[0];
				
				anchor.tab = this.tabs[i];
				anchor.onfocus = function(evt){
						evt = window.event || evt;
						obj.selectTab(this.tab, evt);
					}
				anchor.onclick = function(evt){
						evt = window.event || evt;
						obj.selectTab(this.tab, evt);
					}
			}
		}
		
		
		// Get/Set selection
		this.getSelected();
		if(this.config.select){
			this.selectTab(this.config.select);
		}
		this.adjustFootprint();
	},
	
	/**
	* Select a tab.
	* @param {Tab|Int|String} tab The tab to select, this can either be the Tab object, tab index or the tab's ID.
	* @param {Event} evt The browser event used to call this method.  Passing this will prevent the default event action.
	*/
	selectTab : function(tab, evt){
		
		// Prevent default event action
		if(evt){
			if (evt.preventDefault) {
				evt.preventDefault();
			} 
			else {
				evt.returnValue = false;
			}
		}
		
		// Convert tab number to Tab object
		if(!isNaN(tab)){
			tab = this.tabs[parseInt(tab)];
		}
		
		// Convert tab ID to Tab object
		else if(typeof tab == "string"){
			tab = this.getTabById(tab);
		}
		
		if(!tab){
			return;
		}
		
		// Deselect last tab
		if(this.selected){
			this.selected.container.className = this.selected.container.className.replace(/selected/g, "");
		}
		
		// Select this tab
		tab.container.className += " selected";
		this.selected = tab;
		
		this.adjustFootprint();
	},
	
	/**
	* Get a Tab object by it's ID
	* @param {String} id The tab ID
	* @return {Object} The Tab object or null
	*/
	getTabById : function(id){
		for(var i = 0; i < this.tabs.length; i++){
			if(this.tabs[i].id == id){
				return this.tabs[i];
			}
		}
		return null;
	},
	
	/**
	* Get the selected tab.
	* @return {int} The selected tab index.
	*/
	getSelected : function(){
		for(var i = 0; i < this.tabs.length; i++){
			if(this.tabs[i].container.className.match(/(^|\s)selected(\s|$)/)){
				this.selected = this.tabs[i];
				return i;
				break;
			}
		}
	},
	
	/**
	* Automatically resizes the tab box to fit the content.
	*/
	adjustFootprint : function(){
		if(this.config.autosize == false){
			return;
		}
		
		if(!this.selected){
			return;
		}
		
		// Set height
		var height = this.selected.content.clientHeight + 5;
		if(this.config.vertical == false){
			height += this.selected.header.clientHeight;
		}
		this.tabbox.style.height = height +"px"; 
	},
	
	hideTabbox : function() {
		
		var tabbox = document.getElementById(this.id);
		
		if (tabbox) {
			
			// add a loading message
			var loader = document.getElementById(this.loadingId);
			
			if (loader) {
				loader.innerHTML = 'Loading, please wait&hellip;';
				loader.style.display = 'block'
				loader.style.padding = '50px 12px 50px 12px'
			}
			
			// hide tabbox until rendered
			tabbox.style.visibility = 'hidden';
			this.hidden = true;
			
			// fix the height of the tabbox
			tabbox.style.height = '0px';
		}
	}
}