// AutoTabs - Splits a document into tabs
// (c) 2007 Profundis - www.profundis.se
//
// Features:
// * Ad-hoc method - only requirement is to include a generic javascript (and preferably style to go with it)
// * The index/tabs are generated automagically from h2 elements
// * The active tab is detected and selected from the loaded uri
// * When a tab is clicked the address changes 
// * The local URI part is "uri normalized"
// * The script will add a (stacked) event handler for window load
// * If the headings (h2) doesn't not have a unique parent, one will be created
// * If no content block ("autotabs_content"), it will use all headings in the document
// * If no menu block ("autotabs_menu"), it will be inserted before the content block or the first tab block
// Requirements / limitations:
// * Only one set of tabs in a given document
// * Only h2 elements can represent a tab
// * Each tab block has to have a, possibly anonymous, div around it (including the heading)
// * There must be a block with id "autotabs_content", or all h2 elements in the whole document are counted as tabs.
// * There must be a block with id "autotabs_menu", or it will be inserted before the "autotabs_content" or first tab block
// * Doesn't check if the browser supports everything, which would be a good idea


// A map of tab_id => tab_element
var autotabs_list = new Object();
// Id of the first, or default, tab.
var autotabs_first = null;
// Constants
var autotabs_id_menu = "autotabs_menu";
var autotabs_id_content = "autotabs_content";
var autotabs_tag_heading = "h2";
var autotabs_tab_heading_exclude = "no-tab";


// Set event handler to call autotabs_init when document has loaded, preferably not waiting for objects to load
// Standard
if(window.addEventListener) window.addEventListener('DOMContentLoaded', autotabs_init, false);
// IE
else window.attachEvent('onload', autotabs_init);

// Initialize - make the tab menu and select the correct tab (from uri if possible)
function autotabs_init()
{
	// Builds our internal data structures, and creates the tab menu
	autotabs_make_menu();
	// Select the "right" tab initially (either the first or given by the 
	autotabs_select(autotabs_initial_tab());
}


// Figure out which tab (id) should be displayed initially.
// If the URI contains a local part ("#foo") it will assume "foo", otherwise the first tab identified
function autotabs_initial_tab()
{
	var uri = new String(window.location);
	var id = (uri.indexOf("#") != -1) ? uri.substr(uri.indexOf("#") + 1) : autotabs_first;
	return id;
}


// Analyze the document and build our own internal list, as well as building the tab menu
function autotabs_make_menu()
{
	// Find all headings in the content block, or the entire document if content block not found
	var content = document.getElementById(autotabs_id_content);
	var h_list_all = (content ? content : document).getElementsByTagName(autotabs_tag_heading);

	var h_list = [];

	for(i = 0; i < h_list_all.length; ++i) {
		if(!h_list_all[i].className.match(eval("/\\b" + autotabs_tab_heading_exclude + "\\b/"))) {
			h_list.push(h_list_all[i]);
		}
	}

	// If empty, no point in proceeding
	if(h_list.length == 0) {
		return;
	}

	// Build the menu list
	var menu = document.createElement("ul"); 
	var last_tab_block = null;
	for(i = 0; i < h_list.length; ++i) {
		// Extract info 
		var heading = h_list[i];
		var tab_id = uri_normalize_string(heading.textContent ? heading.textContent : heading.innerText);
		var tab_caption = heading.innerHTML;
		var tab_block = heading.parentNode;
		// Check so the document have blocks
		if(tab_block == last_tab_block) {
			autotabs_make_menu_without_blocks(h_list);
			return;
		}
		else last_tab_block = tab_block;
		// Add to our internal list
		autotabs_list[tab_id] = tab_block;
		if(autotabs_first == null) autotabs_first = tab_id;
		// Insert tab menu item
		var item = document.createElement("li");
		item.id = autotabs_id_menu + "-" + tab_id;
		if(i == h_list.length-1) { item.className = "rightmost"; }
		item.innerHTML = '<a href="#' + tab_id + '" onclick="javascript:autotabs_select(\'' + tab_id + '\');return true;">' + tab_caption + '</a>';
		menu.appendChild(item);
	}

	// Where to insert the menu? Either the specific position, or we have to create and insert it
	var menu_parent = document.getElementById(autotabs_id_menu);
	if(!menu_parent) {
		menu_parent = document.createElement("div");
		menu_parent.id = autotabs_id_menu;
		if(content) {
			// There is a content block; insert the menu just before it
			content.parentNode.insertBefore(menu_parent, content);
		}
		else {
			// No content block, insert before the first tab's block
			var first_tab_block = autotabs_list[autotabs_first]
			first_tab_block.parentNode.insertBefore(menu_parent, first_tab_block);
		}
	}
	// Insert the menu
	menu_parent.appendChild(menu);
}


// This is a nasty thing that will reorganize the document, and add containing block for each
// section. It will replace each heading with a div that contains the heading and all following
// elements until another heading element is found, or there are no more elements (in that level).
function autotabs_make_menu_without_blocks(h_list)
{
	// Create a surrounding block for each heading
	for(i = 0; i < h_list.length; ++i) {
		var heading = h_list[i];
		var tab_block = document.createElement("div");
		// Populate the new block with all following elements, until there are no more or there is another heading
		var el_next = heading.nextSibling;
		while((el = el_next) && String(el.tagName).toLowerCase() != autotabs_tag_heading) {
			el_next = el.nextSibling;
			el.parentNode.removeChild(el);
			tab_block.appendChild(el);
		}
		heading.parentNode.insertBefore(tab_block, heading);
		heading.parentNode.removeChild(heading);
		tab_block.insertBefore(heading, tab_block.firstChild);
	}
	autotabs_make_menu();
}


// Selects a tab - ie hides all but given one. If null, will select the default tab
function autotabs_select(id)
{
	// id == 0 means show the first one
	if(!id) {
		id = autotabs_first;
	}
	// Make sure it exists
	if(!autotabs_list[id]) {
		return;
	}
	// Hide all except id
	for(i in autotabs_list) {
		if(i != id) {
			autotabs_list[i].style.display = "none";
			document.getElementById(autotabs_id_menu + "-" + i).className = "";
		}
	}
	document.getElementById(autotabs_id_menu + "-" + i).className = "rightmost";
	// Make sure it is shown
	autotabs_list[id].style.display = "block";
	document.getElementById(autotabs_id_menu + "-" + id).className += " active";
}


// Make any string usable in uri, without ugly encoding
function uri_normalize_string(str)
{
	str = str.toLowerCase();
	str = str.replace(/&/g, "o");
	str = str.replace(/[هن]/g, "a");
	str = str.replace(/ِ/g, "o");
	str = str.replace(/\s*\/\s*/g, "-");
	str = str.replace(/ /g, "_");
	return str;
}


