/*
	This method returns true if the string object contains the
	argument as a substring, or false if it does not.
	
	Examples:
		var s = "foo";
		s.beginsWith("f") == true;
		s.beginsWith("foo") == true;
		s.beginsWith("foof") == false;
		s.beginsWith("x") == false;
*/
String.prototype.beginsWith = function (needle) {
	/* this would be the haystack ;) */
	return ((this.length >= needle.length)
		&& (this.substring(0, needle.length) == needle));
};




/*	
	===============================================================
	The important thing is to name the ids of your checkboxes in a
	hierarchical fashion.  If you have a parent checkbox called
	"foo", call its direct children things like "foo_a", "foo_b",
	etc.  If "foo_a" has any children, call them "foo_a_a",
	"foo_a_b", etc.

	Here is how those checkboxes will behave, once activated:

	If a checkbox is checked by cilcking, all of its
	descendants will also be checked.

		Example: if "foo" is checked by cilcking, then all the
		checkboxes starting with "foo_" will be checked.
		If "foo_a" is checked by cilcking, then all the
		checkboxes starting with "foo_a_" will be checked.

	If a checkbox is unchecked by cilcking, all of its
	descendents will also be unchecked,

	If a checkbox is unchecked by cilcking, all of its
	ancestors will be unchecked as well.

		Example: if "foo_b_b" is unchecked by cilcking, "foo_b" and
		"foo" will also be unchecked, but other checkboxes under
		"foo_b" or "foo" will be left alone ("foo_b" and "foo" were
		NOT unchecked via clicking).

	A usage example with minimal markup:

	[form name="someform"]
	[pre]
	*	[input type="checkbox"         id="foo"     name="foogroup" value="ALL"]
		*	[input type="checkbox"     id="foo_a"   name="foogroup" value="a"]
			*	[input type="checkbox" id="foo_a_a" name="foo"      value="aa"]
			*	[input type="checkbox" id="foo_a_b" name="foo"      value="ab"]
			*	[input type="checkbox" id="foo_a_c" name="foo"      value="ac"]
		*	[input type="checkbox"     id="foo_b"   name="foogroup" value="b"]
			*	[input type="checkbox" id="foo_b_a" name="foo"      value="ba"]
			*	[input type="checkbox" id="foo_b_b" name="foo"      value="bb"]
	[/pre]
	[/form]
	[script]
		// Activate those checkboxes.
		activateCheckboxHierarchy(document.someform, "foo");
	[/script]
	===============================================================
*/

/*
	Called via onclick handlers on checkboxes that are set up via
	activateCheckboxHierarchy().
*/
function checkboxHierarchyHandler() {
	/*	if being checked, check all descendants.
		if being unchecked, uncheck all descendants. */
	for (var i = 0; i < this._descendants.length; ++i) {
		this._descendants[i].checked = this.checked;
	}
	/*	if being unchecked, also uncheck any ancestors. */
	if (this.checked == false) {
		for (var i = 0; i < this._ancestors.length; ++i) {
			this._ancestors[i].checked = false;
		}
	}
}

/*
	Can be called in an onload handler, or via an inline script
	element placed after all checkboxes.
*/
function activateCheckboxHierarchy(theForm, groupName) {
	/*
		go through all theForm's elements, find any checkboxes
		that are either called groupName or are a descendant, and
		add them to the group.
	*/
	var group = new Array(); /* checkboxes collected here */
	for (var i = 0; i < theForm.elements.length; ++i) {
		var e = theForm.elements[i];
		if ((e.type == "checkbox")
			&& ((e.id == groupName)
				|| e.id.beginsWith(groupName + "_"))) {
			e._ancestors = new Array();
			e._descendants = new Array();
			group.push(e);
		}
	}
	/* establish ancestor-descendant relationships between
	   checkboxes */
	for (var i = 0; i < group.length; ++i) { /* ancestors */
		var iname = group[i].id;
		for (var j = 0; j < group.length; ++j) { /* descendants */
			var jname = group[j].id;
			if ((i != j) && jname.beginsWith(iname + "_")) {
				group[j]._ancestors.push(group[i]);
				group[i]._descendants.push(group[j]);
			}
		}
	}
	/* establish onclick handlers for all the checkboxes */
	for (var i = 0; i < group.length; ++i) {
		group[i].onclick = checkboxHierarchyHandler;
	}
}

