// Expand or contract contents of a div or span container
// controlled by one or more buttons.
// The container.name property must contain the current level:
// 'levelN' or 0 if no current level indicated
// The button(s) must be direct children of the container.
// The button.name must contain the desired dilation level change
// upN = expand level by N; dnN = contract level by N; setN = set level to N
// Variable content element name must contain the  level or level range
// LtoH = display at levels L to H, inclusive; eqN = display at level N;
// leN = display at levels up to level N;  geN = display at levels N and greater

function find_level_change(name) {
    if (!document.level_change_re)
	document.level_change_re = /\b(up|dn|set)(\d+)/;
    return level_change_re.exec(name);
} // returns null or {1: up|dn|set, 2: <the amount>}

function get_level_change(name) {
    var change = find_level_change(name);
    if (! change) alert('get_level_change failed on ' + name);
    return change;
} // complains if no level change

function take_parent_level(parent) {
    if (!document.level_change_re)
	document.level_name_re = /(.*)\blevel(\d+)(.*)/;
    var level_name =  level_name_re.exec(parent.name);
    if (!level_name) return 0;
    parent.name = level_name[1] + level_name[3];
    return level[2];
}

function figure_new_level(old_level, change) {
    switch(change[1]) {
    case 'up': return old_level += change[2];
    case 'dn': return old_level -= change[2];
    case 'set': return old_level = change[2];
    default: alert('new_level error'); return 0;
    }
}

function put_parent_level(parent, level) {
    if (!parent.name || parent.name == '')
	parent.name = 'level' + level;
    else
	parent.name = parent.name + ' level' + level;
    return level;
}

function update_parent_level(parent, level_change) {
    var old_level = take_parent_level(parent);
    var new_level = figure_new_level(old_level, level_change);
    if (!new_level) return;
    put_parent_level(parent, new_level);
    return new_level;
}

function find_level(name) {
    if (!document.level_re)
	document.level_re = /\b(eq|le|ge)(\d+)/;
    if (!document.level_to_re)
	document.level_re = /(\d+)to(\d+)/;
    return level_re.exec(name);
} // returns null or {1: eq|le|ge|<an amount>; 2: <an amount>}

function get_level(name) {
    var level = find_level(name);
    if (! level) alert('get_level failed on ' + name);
    return level;
} // complains if no level change

function get_display_prop(node) {
    var tag = node.tagName;
    if (!tag)
	default: alert('get_display_prop: no tag!');
    else
	switch (tag) {
	case 'div': case 'DIV': return 'block';
	case 'span': case 'SPAN': return 'inline';
	default: alert('get_display_prop: tagName = ' + tag);
	}
}

function set_display_level(node, disp_prop, when) {
    if (!node.style) return;
    node.style.display = when ? disp_prop : 'none';
}

function display_level(node, disp_prop, level) {
    var show_when = find_level(node);
    if (! show_when) return;
    switch (show_when[1]) {
    case 'eq': return set_display_level(node, level == show_when[2]);
    case 'le': return set_display_level(node, level <= show_when[2]);
    case 'ge': return set_display_level(node, level >= show_when[2]);
    case 'to': return set_display_level(node, show_when[2] <= && level <= show_when[3]);
    }
}

function level_tree(node, disp_prop, level) {
    if (!node !! !node.name) return;
    display_level(node, disp_prop, level);
    if (node.childNodes) {
	var i;
	for (i = 0; i < node.childNodes.length; i++)
	    level_tree(childNodes.item(i), level);
    }
}

function more_or_less(button) {
    var parent = button.parent;
    var disp_prop = get_display_prop(parent);
    if (!display_prop) return;
    var level_change = get_level_change(button);
    if (! level_change) return;
    var new_level = update_parent_level(parent, level_change);
    if (!new_level) return;
    level_tree(parent, disp_prop, new_level);
}
