/*
 * Helper functions for class handling
 * supports multiple classes, like class="foo bar"
 */

// returns if an element has a class
function class_test(el, cls) {
	return new RegExp('(^|\\s)'+cls+'(\\s|$)').test(el.className);
}
// adds a class to an element
function class_add(el, cls) {
	if (class_test(el, cls))
		return false;

	if (el.className)
		el.className += ' ' + cls;
	else
		el.className = cls;
	return true;
}
// replaces a class
function class_replace(el, oldcls, newcls) {
	var re = new RegExp('(^|\\s)'+oldcls+'(\\s|$)');
	var reres = re.exec(el.className);
	if (!reres)
		return false;
	el.className = el.className.replace(re, reres[1]+newcls+reres[2]);
	return true;
}
// removes a class from an element
function class_remove(el, cls) {
	return class_replace(el, cls, '');
}


/*
 * Collapsible list implementation
 */

// collapses/expands an element
function collapsible_set_element(el, val) {
	if (val) {
		class_replace(el, 'expanded', 'collapsed');
		el.lastChild.style.display = 'none';
	} else {
		class_replace(el, 'collapsed', 'expanded');
		el.lastChild.style.display = '';
	}
}

// makes an element collapsible
function collapsible_setup_element(el, dfl) {
	// test to avoid hang
	if (el.childNodes.length<2) return;
	class_add(el, dfl ? 'collapsed' : 'expanded');
	// use last child element as collapsible tem
	var elcontent = el.removeChild(el.lastChild);
	class_add(elcontent, 'collapse-content');
	var eltitle = document.createElement('div');
	eltitle.className = 'collapse-title';
	eltitle.style.cursor = 'pointer'; // for IE6 here instead of CSS
	while(el.hasChildNodes()) {
		eltitle.appendChild(el.removeChild(el.firstChild));
	}
	// then add these to the original element
	el.appendChild(eltitle);
	el.appendChild(elcontent);

	// Now setup handler to expand/collapse
	eltitle.onclick = function() {
			collapsible_set_element(el, !class_test(el, 'collapsed'));
			return false;
	}
	collapsible_set_element(el, dfl);

	// add a class to parent for layouting purposes
	class_add(el.parentNode, 'collapse-is-parent');
}

// make an element's children collapsible
function collapsible_prepare_children(el, dfl) {
	for (var i=0; i<el.childNodes.length; i++) {
		var child = el.childNodes[i];
		// only handle elements
		if (child.nodeType!=1)
			continue;
		// we need at least text and an element to collapse something
		if (child.childNodes.length<2) {
			class_add(child, 'nocollapse');	
			continue;
		}
		// add collapsed/expanded tag if not something present
		if (!class_test(child, '(collapsed|expanded|nocollapse)'))
			class_add(child, dfl ? 'collapsed' : 'expanded');
	}
}

// recursively find nodes that need to be handled
function collapsible_discover_elements(el) {
	var discels = new Array();

	for (var i=0; i<el.childNodes.length; i++) {
		var child = el.childNodes[i];
		// only handle ordinary elements
		if (child.nodeType!=1)
			continue;
		// handle nodes whose children need to be collapsible
		if (class_test(child, 'collapsed-children'))
			collapsible_prepare_children(child, true);
		if (class_test(child, 'expanded-children'))
			collapsible_prepare_children(child, false);
		// make collapsible 
		if (class_test(child, '(collapsed|expanded)'))
			discels.push(child);
		// search inside too
		discels = discels.concat(collapsible_discover_elements(child));
	}

	return discels;
}

// make all elements that need be collapsible
function collapsible_discover() {
	// make elements collapsible
	var els = collapsible_discover_elements(document.getElementsByTagName('body')[0]);
	for (var i=0; i<els.length; i++)
		collapsible_setup_element(els[i], class_test(els[i], 'collapsed'));
	// make button to toggle visibility of all elements
	var btn = document.getElementById('expand-all-toggle');
	if (btn) {
		class_add(btn, 'expand-all-toggle');
		btn.innerHTML = 'expand all';
		btn.onclick = function() {
			var curstate = btn.innerHTML!='expand all';
			for (var i=0; i<els.length; i++) {
				collapsible_set_element(els[i], curstate);
			}
			btn.innerHTML = (curstate ? 'expand' : 'collapse') + ' all';
		}
	}
}

onload = collapsible_discover;


