/*
# $Id$
# Copyright 2008 James D Gauld (james@thundermonkey.net)
# MIT License.
*/

/*
# @class TabbedForm( HTMLElement form, object options )
#
# Creates a tabbed interface from any form containg <fieldset> blocks.
# Each <fieldset> block becomes a separate "page" within the form, and each of
# these pages is assigned a tab which is used to activate it.
#
# Usage:
#	var t = new TabbedForm(form, options);
#	t.selectTab(2);
#
# Valid options:
#	RexExp accesskeyRegex	= Regular expr. for extracting the accesskey in a legend
#	Array excludeFieldsets	= List of fieldsets to exclude
#	Array tabEvents			= Events added to a tab (index matches tab order in HTML)
*/
var TabbedForm = function(form, options) {

	/*
	# @property private HTMLElement form
	# Form element containing the tabs.
	*/
	var form = form;

	/*
	# @property private object options
	# Options container.
	*/
	var options = options;

	/*
	# @method public void build()
	#
	# Build the interface.
	*/
	this.build = function() {

		// Manipulate options
		if(options.excludeFieldsets) {
			options.excludeFieldsets.flatten();
		}

		// Set form attributes
		form.addClass('tabbed-form');

		// Create container for interfaces and insert at top of form
		var container = new Element('div');
		container.inject(form.getElements('fieldset')[0], 'before');
		container.setStyles({
			position: 'relative'
		});
	
		// Build tabs
		// - extract the text within each <legend> node to use as the tab label
		// - remove all <legend> nodes
		// - hide all fieldset blocks
		var tabs = (new Element('ul')).addClass('tabs');
		var legends = form.getElements('legend');
		for(var i=0; i<legends.length; i++) {

			// Check this legend's fieldset is not to be excluded
			if(options.excludeFieldsets && options.excludeFieldsets.contains(legends[i].getParent('fieldset'))) {
				continue;
			}

			// Move fieldset to container
			container.grab(legends[i].getParent('fieldset'));

			// Create tab
			var a = new Element('a', {
				href: '#tab'+i,
				html: legends[i].innerHTML,
				events: {
					click: function(e) {
						var index = this.href.toString().replace(/[^#]*#tab([0-9]+)$/, '$1');
						this.tabbedForm.selectTab(index);
						return false;
					}
				}
			});
			a.tabbedForm = this;
			var m;
			if(options.accesskeyRegex && (m = legends[i].innerHTML.match(options.accesskeyRegex))) {
				a.setProperty('accesskey', m[1]);
			}
			if(options.tabEvents && options.tabEvents[i]!==null) {
				a.addEvents(options.tabEvents[i]);
			}
			a.inject((new Element('li')).inject(tabs));
			legends[i].getParent('fieldset').setStyles({
				display: 'none'
			});
			legends[i].setStyles({
				display: 'none'
			});
			legends[i].dispose();		// This is required to fix a bug in IE that breaks layout if legend is set to display:none
		}
		tabs.inject(container, 'before');

		// Select the tab based on either the current url or, if that doesn't
		// contain a valid tab identifier, the first available.
		if(m = self.location.hash.toString().match(/#tab([0-9]+)$/)) {
			form.getElement('ul.tabs').getChildren()[m[1]].getElement('a').fireEvent('click');
		}
		else {
			//this.selectTab(0);
			form.getElement('ul.tabs').getChildren()[0].getElement('a').fireEvent('click');
		}
	}

	/*
	# @method public void selectTab( int index )
	# index	= The tab to activate (0 indexed)
	#
	# Activates the specified tab, displaying it's associated fieldset and
	# hiding all others.
	# If the tab is disabled then it will not be activated.
	# Set index to -1 to deactivate all tabs.
	*/
	this.selectTab = function(index, triggerEvent) {

		// Check if tab exists
		if(!form.getElement('ul.tabs').getChildren()[index]) {
			index = 0;
		}

		// Check if tab is disabled
		if(index>=0) {
			var tab = form.getElement('ul.tabs').getChildren()[index];
			if(tab.hasClass('disabled')) {
				return false;
			}
		}

		// Trigger event
		if(triggerEvent) {
			form.getElement('ul.tabs').getChildren()[index].getElement('a').fireEvent('click');
			return true;
		}

		// Show selected tab, hide all others
		var interfaces = form.getElements('fieldset');
		for(var i=0; i<interfaces.length; i++) {
			interfaces[i].style.display = i==index ? 'block' : 'none';
		}
		form.getElement('ul.tabs').getChildren().each(function(c, i) {
			i==index ? c.addClass('open') : c.removeClass('open');
		});
		return true;
	}

	this.enableTab = function(index) {
		var tab = form.getElement('ul.tabs').getChildren()[index];
		tab.removeClass('disabled');
	}

	this.disableTab = function(index) {
		var tab = form.getElement('ul.tabs').getChildren()[index];
		tab.addClass('disabled');
		if(tab.hasClass('open')) {
			var toOpen = null;
			form.getElement('ul.tabs').getChildren().each(function(c, i) {
				if(i!=index && !c.hasClass('disabled') && toOpen===null) {
					toOpen = c.getElements('a')[0];
				}
			});
			toOpen===null ? this.selectTab(0) : toOpen.fireEvent('click');
		}
	}

	this.getSelectedTab = function() {
		var tabIndex = -1;
		form.getElement('ul.tabs').getChildren().each(function(c, i) {
			if(c.hasClass('open')) {
				tabIndex = i;
			}
		});
		return tabIndex;
	}

	/*
	# @procedure void constructor
	*/
	this.build();
}

