
// Hard-code maximum length of a few arrays below.
var MAXIDX = 50;

// Number of nodeNN "popups".
var MAXDIV = 16;

// Some judiciously chosen globals to avoid gratuitous
// argument / return-value passing in recursive routines.
var HTML;
var TREE;
var MAXCOLS;
var COLS = new Array(MAXIDX);
var EXPAND = new Array(MAXIDX);
var EXPAND2 = new Array(MAXIDX);
var EXPAND_ALL = 0;

// Initialize some of them.
for (var i=0; i<MAXIDX; i++) {
    EXPAND[i] = "";
    EXPAND2[i] = "";
}

// Make this node look obnoxious so we can see it.
var HIGHLIGHT;
var HIGHLIGHT_Y; // (y offset from tree top)

// Flag to tell it only to print "important" branches.
var IMPORTANT = 1;
var IMPORTANT_TREE;
var ANY_PRUNED;

// Background colors used to separate expandable tree sections.
var COLORS = [
    "#000028",
    "#000040",
    "#000050",
    "#000060",
    "#00006C",
    "#000078",
    "#000080",
    "#000088",
    "#000090",
    "#000096",
    "#00009C",
    "#0000A0",
    "#0000A4",
    "#0000A8",
    "#0000B0",
];
var NUM_COLORS = 15;

//// Background colors used to separate expandable tree sections.
//var COLORS = [
//    "#000040",
//    "#200040",
//    "#002040",
//    "#400040",
//    "#004040",
//    "#400020",
//    "#004020",
//];
//var NUM_COLORS = 7;

// ----------------------------
//  Cookie stuff.
// ----------------------------

function get_cookie() {
    var cookie = find_cookie(FILENAME);
    if (cookie != null) {
        IMPORTANT = parseInt(parse_cookie(cookie, "IMPORTANT"));
        EXPAND_ALL = parseInt(parse_cookie(cookie, "EXPAND_ALL"));
        var expand_args = parse_cookie(cookie, "EXPAND");
        if (expand_args != null) {
            for (var i=0; i<MAXIDX; i++) {
                var x = expand_args.replace(/,.*/, "");
                EXPAND[i] = x;
                expand_args = expand_args.replace(/^[^,]*/, "");
                expand_args = expand_args.replace(/^,/, "");
            }
        }
    }
}

function set_cookie() {
    var expand_args = "";
    for (var i=0; i<MAXIDX; i++) {
        if (EXPAND[i] != "") {
            if (expand_args != "")
                expand_args += ",";
            expand_args += EXPAND[i];
        }
    }

    var data =
        "IMPORTANT:" + (IMPORTANT ? 1 : 0) + "|" +
        "EXPAND_ALL:" + (EXPAND_ALL ? 1 : 0) + "|" +
        "EXPAND:" + expand_args;
    document.cookie = FILENAME + "=" + escape(data);
}

// ----------------------------
//  Initialize layers, etc.
// ----------------------------

function init_page() {

    // Hide info popup.
    hide_popup("popup");
    hide_popup("box1");
    hide_popup("box2");
    hide_popup("box3");
    hide_popup("box4");

    // Hide collapsible nodes.
    for (var i=1; i<=MAXDIV; i++)
        hide_popup("node" + i);

    // Get default settings.
    get_cookie();

    // Always expand at least first level.
    EXPAND[0] = FULL_TREE[0];

    // Prune tree for "important" business.
    ANY_PRUNED = false;
    IMPORTANT_TREE = prune_tree(FULL_TREE);
    if (!ANY_PRUNED) IMPORTANT_TREE = null;
    IMPORTANT = (IMPORTANT_TREE == null ? 0 : IMPORTANT);

    // Check URL for expansion info.
    get_expand_from_url();

    // Install mouse watcher to do popups.
    install_onmousemove(mouse_moved);

    // Draw tree.
    draw_tree();
}

// -------------------------------------
//  This is the "public" access point.
// -------------------------------------

var inited_wait = 0;
function draw_tree() {

    // Create the "please wait" popup.
    if (!inited_wait++) {
        write_popup("wait",
            '<table bgcolor="#808080" cellspacing=1 cellpadding=0><tr><td>' +
            '  <table bgcolor="#101010" cellspacing=0 cellpadding=5><tr><td>' +
            '    Please wait a moment.  This can take a really long time<br>' +
            '    on some browsers (like Internet Explorer).  I developed<br>' +
            '    it for Netscape / Mozilla.  Other browsers beware.<br>' +
            '  </table>' +
            '</table>'
        );
    }

    // Display "please wait" popup in the center of the window.
    var win = get_window_size();
    var pos = get_position("wait");
    var xoff = get_window_x_offset();
    var yoff = get_window_y_offset();
    show_popup("wait", Math.floor(xoff + win.w/2 - pos.w/2),
                       Math.floor(yoff + win.h/2 - pos.h/2));

    // Give browser time to display it.
    window.setTimeout(draw_tree_2, 100);
}
function draw_tree_2() {

    // Disable popup for a while.
    watch_mouse(mouse_moved, 0);
    NUM_POPS = 0;
    DONE_RHS = 0;

    // Hide popup.
    hide_popup("popup");
    hide_popup("box1");
    hide_popup("box2");
    hide_popup("box3");
    hide_popup("box4");
    for (var i=1; i<=MAXDIV; i++) {
        var id = "node" + i;
        hide_popup(id);
    }

    // Which tree are we drawing?
    TREE = IMPORTANT ? IMPORTANT_TREE : FULL_TREE;

    // How many levels deep (need for HTML table).
    MAXCOLS = tree_depth(TREE, 1);

    // Show branch that's been expanded.
    var expansion = "";
    var any_expanded = false;
    for (var i=0; i<MAXIDX; i++) {
        if (EXPAND[i] != "") {
            if (expansion != "") {
                expansion += " - ";
                any_expanded = true;
            }
            expansion += "<font color=\"#E06040\">" +
                (i == 0 ? "<b>" : "") + debar(EXPAND[i]) +
                (i == 0 ? "</b>" : "") + "</font>";
        }
    }
    expansion = "<font color=\"#A02000\"><nobr>" +
        expansion + "</nobr></font>";

    // Add some controls at the bottom.
    var buttons = "";
    if (any_expanded || EXPAND_ALL) {
        buttons += "<a href=\"javascript:collapse()\" class=button>" +
            "Collapse tree.</a><br>";
    }
    if (!EXPAND_ALL) {
        buttons += "<a href=\"javascript:expand_all()\" class=button>" +
            "Expand every branch.</a><br>";
    }
    if (IMPORTANT_TREE != null) {
        if (IMPORTANT) {
            buttons += "<a href=\"javascript:set_important(0)\" class=button>" +
                "Show unimportant stuff.</a><br>";
        } else {
            buttons += "<a href=\"javascript:set_important(1)\" class=button>" +
                "Only show important stuff.</a><br>";
        }
    }
    if (TOP_LINK != "") {
        buttons += "<a href=\"javascript:goto_parent()\" class=button>" +
            "Go back to parent tree.</a><br>";
    }

    // Initialize HTML.
    HTML = "";
    HIGHLIGHT_Y = -1;

    // Tell damned IE what size all the columns should be.
    if (isIE) {
        var num_cols = MAXCOLS * 2 - 1;
        HTML += "<tr height=1>";
        for (var i=0; i<MAXCOLS*2-1; i++) {
            if (i & 1) {
                HTML += "<th width=2>";
            } else {
                HTML += "<th width=15>";
            }
        }
        HTML += "<th width=100><th width=15><th width=5><th width=15>\n";
    }

    // Draw tree.
    recurse_draw_tree(TREE, 0, 1);

    // Enclose tree body in tables.
    HTML =
"<p>" + expansion + "\n" +
"<p><table cols=1 cellpadding=1 cellspacing=0 bgcolor=\"#807060\"><tr><td>\n" +
"  <table" + (isIE ? " cols=" + (MAXCOLS*2+3) : "") + " cellpadding=0 cellspacing=0 bgcolor=\"#000010\">\n" +
"    <tr height=10><td><a name=topleft id=topleft>&nbsp;</a>\n" +
     HTML + "\n" +
"    <tr height=10><td>\n" +
"  </table>\n" +
"</table>\n" +
"<p>" + buttons + "\n";

    // Install into "popup" layer.
    write_popup("tree", HTML);

    // Save settings in cookie.
    set_cookie();

    // Draw little boxes at collapsible nodes.
    draw_nodes();

    // Finalize locations of popup zones.
    locate_boxes();

    // Okay to start doing popups again.
    watch_mouse(mouse_moved, 1);

    // Get rid of "please wait" popup.
    hide_popup("wait");
}

// ----------------------------
//  Draw a tree!
// ----------------------------

function is_leaf(node) {
    if (typeof(node) != "object")
        return true;
    if (EXPAND_ALL)
        return false;
    if (node[0] == "")
        return false;
    if (is_in_expand(node[0]))
        return false;
    if (node[1] > 1)
        return true;
    if (is_trivial(node[2]))
        return false;
    return true;
}

function recurse_draw_tree(tree, cols, row) {

    // Draw whole line once we finally reach a leaf node.
    if (is_leaf(tree)) {
        var bgcolor = "";
        var bgcolor_idx = (TREE[0] == "Top" ? -1 : -2);

        // Put together list of args to expand() callback.
        var expand_args = "";
        var num_expand_args = 0;

        // We are writing a single "<tr><td>...<td>..." row to HTML.
        HTML += "    <tr height=18>\n";

        // This is the physical column -- different from "i" if and
        // only if there are some nodes with only one sub-branch.
        var col = -1;

        // We might skip the column that actually contains the anchor,
        // in which case I set this and add an anchor to the next column
        // that is actually shown.
        var need_anchor = 0;
        var anchor_label = "";

        // Loop over logical columns.
        for (i=0; i<cols; i++) {

            // Add label to expand() args.  (0th level always on.)
            if (i > 0 && EXPAND2[i] != "") {
                if (expand_args != "")
                    expand_args += ",";
                expand_args += "'" + EXPAND2[i] + "'";
                num_expand_args++;
            }

            // Skip first column of top tree (so I can put viruses in
            // an entirely separate tree of "life").
            if (TREE[0] != "Top" || i > 0) {

                // Okay, logistics of HTML requires that lines can only
                // be positioned at top, middle, or bottom of a given row.
                var obj = COLS[i];
                var top_row = Math.floor(obj.b + 0.5);
                var mid_row = Math.floor(obj.c + 0.5);
                var bot_row = Math.floor(obj.d + 0.5);
                var top_pos = Math.floor((obj.b + 0.5 - top_row) * 3);
                var mid_pos = Math.floor((obj.c + 0.5 - mid_row) * 3);
                var bot_pos = Math.floor((obj.d + 0.5 - bot_row) * 3);

                // What is background color?
                bgcolor_idx += obj.f;
                if (bgcolor_idx >= NUM_COLORS)
                    bgcolor_idx = NUM_COLORS - 1;
                // if (bgcolor_idx > 0)
                //     bgcolor_idx = bgcolor_idx % NUM_COLORS;
                bgcolor = (bgcolor_idx < 0 ? "" :
                    " bgcolor=\"" + COLORS[bgcolor_idx] + "\"");

                // Put up flag saying we need an anchor soon as possible.
                if (i > 0 && EXPAND2[i] != "") {
                    if (!need_anchor)
                        need_anchor = num_expand_args + 1;
                    anchor_label = EXPAND2[i];
                }

                // Only show this level if there is more than one branch.
                if (top_row != bot_row) {
                    col++;

                    // Draw horizontal line.  Include anchor for collapsible node.
                    if (row == mid_row) {
                        HTML += "<td width=15" + bgcolor +
                            " valign=" + (mid_pos == 0 ? "top" : mid_pos == 1 ? "middle" : "bottom") + ">" +
                            (need_anchor ? ("<a name=\"anchor" + need_anchor + "\" id=\"anchor" + need_anchor + "\">") : "") +
                            "<table width=15 height=2 cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>" +
                            (need_anchor ? "</a>" : "") +
                            "\n";
                    } else {
                        HTML += "<td width=15" + bgcolor + ">\n";
                    }

                    // Draw vertical line.
                    if (top_row == bot_row && row == top_row)
                        HTML += "<td width=2" + bgcolor + " valign=" + (mid_pos == 0 ? "top" : mid_pos == 1 ? "middle" : "bottom") + "><table width=2 height=2 cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>\n";
                    else if (row == top_row)
                        HTML += "<td width=2" + bgcolor + " valign=bottom><table width=2 height=" + (top_pos == 0 ? 18 : top_pos == 1 ? 10 : 2) + " cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>\n";
                    else if (row == bot_row)
                        HTML += "<td width=2" + bgcolor + " valign=top><table width=2 height=" + (bot_pos == 0 ? 2 : bot_pos == 1 ? 10 : 18) + " cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>\n\n";
                    else if (row > top_row && row < bot_row)
                        HTML += "<td width=2" + bgcolor + "><table width=2 height=18 cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>\n";
                    else
                        HTML += "<td width=2" + bgcolor + ">\n";

                    // Keep a list of popup zones.
                    if (need_anchor) {
                        var j = 0;
                        for (; j<NUM_POPS; j++) {
                            if (POPS_LABELS[j] == anchor_label)
                                break;
                        }
                        if (j < MAX_NUM_POPS) {
                            if (obj.a == obj.e) {
                                POPS_X1[j] = col * 17;
                                POPS_Y1[j] = row * 18 - 8;
                                POPS_Y2[j] = row * 18 + 10;
                            } else if (row == obj.a) {
                                POPS_X1[j] = col * 17;
                                POPS_Y1[j] = row * 18 - 8;
                            } else if (row == obj.e) {
                                POPS_X1[j] = col * 17;
                                POPS_Y2[j] = row * 18 + 10;
                            }
                            if (j >= NUM_POPS) {
                                POPS_LABELS[j]  = anchor_label;
                                var m = 0;
                                for (var k=1; k<=i; k++)
                                    if (EXPAND2[k] != "") m++;
                                POPS_LATINS[j] = new Array(m + 1);
                                POPS_LATINS[j][0] = m;
                                var l = 1;
                                for (var k=1; k<=i; k++)
                                    if (EXPAND2[k] != "")
                                        POPS_LATINS[j][l++] = EXPAND2[k];
                                NUM_POPS = j + 1;
                            }
                        }
                        need_anchor = 0;
                    }
                }
            }
        }

        // Add current leaf to expand() args.
        if (typeof(tree) == "object") {
            if (expand_args != "")
                expand_args += ",";
            expand_args += "'" + tree[0].replace(/\?$/, "") + "'";
        }

        // Draw last horizontal line.  Always middle, and have it
        // stop a little short of the right edge to give a gap
        // between tree and text.
        HTML += "<td width=15" + bgcolor + " valign=middle><table width=15 height=2 cellspacing=0 cellpadding=0 bgcolor=\"#808080\"><tr><td></table>\n";

        // Draw text, with callback if this node is expandable.
        var cols_left = MAXCOLS * 2 - col * 2 - 3;
        HTML += "<td" + bgcolor + " max=" + MAXCOLS + " col=" + col + (cols_left > 1 ? " colspan=" + cols_left : "") + " align=left>";
        var x = typeof(tree) == "object" ? tree[0] : tree;
        var bare = x.replace(/\?$/, "");
        var link = get_link(bare);
        x = debar(x);
        if (bare == HIGHLIGHT) {
            x = "<font color=\"#FF0000\">" + x + "</font>";
            HIGHLIGHT_Y = row * 18;
        }
        x = "<nobr>" + x + "</nobr>";
        if (typeof(tree) == "object")
            x = "<a href=\"javascript:expand(" + expand_args + ")\" class=internal_node><b>" + x + "</b></a>";
        if (link != "")
            x = "<a href=\"" + link + "\" class=external_node><b>" + x + "</b></a>";
        HTML += "&nbsp;" + x + "\n";

        // Common name.
        var common = get_common(bare).
            replace(/\(/, "<small>(").
            replace(/\)/, ")</small>");
        HTML += "<td>" + (row == 1 ? "<a name=topright id=topright>" : "") +
                "&nbsp;&nbsp;" + (row == 1 ? "</a>\n" : "\n");
        HTML += "<td>" + (common == "" ? "" :
            "<font color=\"#C0A040\"><nobr>" + common +
            "</nobr></font>") + "\n";

        // Margin on right side.
        HTML += "<td>&nbsp;&nbsp;\n";

        // Tell caller which row we're on now.
        return row + 1;
    }

    // Keep track of which labels need to be expanded to get
    // to this branch of the tree.
    EXPAND2[cols] = tree[0].replace(/\?$/, "");

    // Make first pass to figure out where to draw lines.
    COLS[cols++] = scout_tree(tree, row);

    // Recurse to draw branches beneath this node.
    for (var i=0; i<tree[1]; i++)
        row = recurse_draw_tree(tree[i+2], cols, row);
    return row;
}

// ----------------------------
//  Tree utilities.
// ----------------------------

// Is there only one leaf under this node?
function is_trivial(node) {
    if (typeof(node) != "object")
        return true;
    if (node[0] != "")
        return true;
    if (node[1] > 1)
        return false;
    return is_trivial(node[2]);
}

// Count number of leaves under this node.  (Not used.)
function num_leaves(node) {
    if (typeof(node) != "object")
        return 1;
    var num = 0;
    for (var i=0; i<node[1]; i++)
        num += num_leaves(node[i+2]);
    return num;
}

// Unfortunately I need the depth before I do anything else.
function tree_depth(tree, col) {
    var max = col;
    if (is_leaf(tree))
        return max;
    for (var i=0; i<tree[1]; i++) {
        var x = tree_depth(tree[i+2], col+1);
        if (max < x) max = x;
    }
    return max;
}

// Calculate locations of some important things.
function scout_tree(tree, row) {

    // Note: the "row" argument is crazy.  It is the top-most
    // row on first invocation, but  then gets set to 1 for
    // all recursive calls.  Don't ask.

    // Leaf node is easy: just one row.
    if (is_leaf(tree)) {
        var x = new Object;
        x.a = x.b = x.c = x.d = x.e = row;
        return x;
    }

    // Calculate: (will get rounded off later)
    //    a = top-most sub-branch
    //    b = top of vertical line at this level
    //    c = root connection to this level
    //    d = bottom of vertical line at this level
    //    e = bottom-most sub-branch
    //    f = flag: change color?
    var x = new Object;
    for (var i=0; i<tree[1]; i++) {
        var y = scout_tree(tree[i+2], 1);
        if (i == 0) {
            x.a = row-1 + y.a;
            x.b = row-1 + y.c;
            x.d = row-1 + (tree[1] > 1 ? y.e : y.c);
            x.e = row-1 + y.e;
        } else if (i == tree[1]-1) {
            x.d += y.c;
            x.e += y.e;
        } else {
            x.d += y.e;
            x.e += y.e;
        }
    }
    x.c = (x.b + x.d) / 2;
    //x.f = (tree[0] != "" && is_in_expand(tree[0]) ? 1 : 0);
    x.f = (tree[0] != "" && (tree[1] > 1 || !is_trivial(tree[2])) ? 1 : 0);
    return x;
}

// Look for a given node in the tree.  Fill EXPAND2[] with names of the
// nodes that need to be expanded to get to that node, while we're at it.
function find_node(tree, node, col) {

    // What is the name of this node?
    var label = typeof(tree) == "object" ? tree[0] : tree
    label = label.replace(/\?$/, "");

    // Abort and return success when we find it!
    if (node == label) return true;

    // Reached end of a branch, return failure.
    if (typeof(tree) != "object") return false;

    // Keep track of what needs to be expanded to get here.
    EXPAND2[col] = label;

    // Recurse to child sub-branches.
    for (var i=0; i<tree[1]; i++)
        if (find_node(tree[i+2], node, col+1))
            return true;

    // Backtrack.
    EXPAND2[col] = "";
    return false;
}

// Prune "unimportant" branches off a tree.
function prune_tree(old_tree) {

    // Is this branch important?
    var word = typeof(old_tree) == "object" ? old_tree[0] : old_tree;
    word = word.replace(/\?$/, "");
    if (word != "" && !is_important(word)) {
        ANY_PRUNED = true;
        return null;
    }

    // Reached leaf.
    if (typeof(old_tree) != "object")
        return old_tree;

    // Find out which branches survive cut.
    var tmp_tree = new Array(old_tree[1]);
    var num = 0;
    for (var i=0; i<old_tree[1]; i++) {
        tmp_tree[i+2] = prune_tree(old_tree[i+2]);
        if (tmp_tree[i+2] != null) num++;
        else ANY_PRUNED = true;
    }

    // None make it.  Careful: if this is a labelled branch,
    // then turn it into a leaf (wouldn't even have gotten here
    // if the label itself was also unimportant.)
    if (num == 0)
        return old_tree[0] == "" ? null : old_tree[0];

    // Create new tree.
    var new_tree = new Array(num+2);
    new_tree[0] = old_tree[0];
    new_tree[1] = num;
    var j = 2;
    for (var i=0; i<old_tree[1]; i++) {
        if (tmp_tree[i+2] != null)
            new_tree[j++] = tmp_tree[i+2];
    }

    // If only one branch, then remove a level if we can.
    if (num == 1 && new_tree[0] == "")
        return new_tree[2];

    return new_tree;
}

// ----------------------------
//  Draw collapsible nodes.
// ----------------------------

function draw_nodes() {
    var expand_args = "";

    for (var i=1; i<=MAXDIV; i++) {
        var node_id = "node" + i;
        var anchor_id = "anchor" + i;

        if (i > 1 && !EXPAND_ALL && EXPAND[i-1] != "") {

            // Create HTML for box.
            var html =
'<table width=14 height=16 bgcolor="#A06060" cellspacing=1 cellpadding=0><tr><td>' +
 (isIE ? '  <a onclick="expand(' + expand_args + ')" class=collapse_node>' :
         '  <a href="javascript:expand(' + expand_args + ')" class=collapse_node>') +
'    <table width=12 height=14 bgcolor="#201810" cellspacing=0 cellpadding=0><tr>' +
'      <tr align=center><td valign=middle>' +
'        <b class=collapse_node>' + EXPAND[i-1].charAt(0) + '</b>' +
'    </table>' +
'  </a>' +
'</table>';
            write_popup(node_id, html);

            // Position and show it.
            var pos = get_position(anchor_id);
            if (pos != null) {
                var x = pos.x + (isIE ? -2 : 8);
                var y = pos.y - 7;
                show_popup(node_id, x, y);
            } else {
                hide_popup(node_id);
            }

            // Add this label to expand args.
            if (expand_args != "")
                expand_args += ",";
            expand_args += "'" + EXPAND[i-1] + "'";
        }

        // Hide all the others.
        else hide_popup(node_id);
    }
}

// ----------------------------
//  Tree branch expansion.
// ----------------------------

// Callback to change which branch is expanded.
function expand() {

    // Clear first.
    for (var i=0; i<MAXIDX; i++)
        EXPAND[i] = "";

    // Always expand root node.
    EXPAND[0] = FULL_TREE[0];

    // Copy in the rest from arg list.
    for (var i=0; i<expand.arguments.length; i++)
        EXPAND[i+1] = expand.arguments[i];

    // Redraw tree.
    draw_tree();
}

// For debugging -- collapse everything.
function collapse() {
    EXPAND_ALL = 0;
    for (var i=1; i<MAXIDX; i++)
        EXPAND[i] = "";
    draw_tree();
}

// For debugging -- expand everything.
function expand_all() {
    EXPAND_ALL = 1;
    for (var i=1; i<MAXIDX; i++)
        EXPAND[i] = "";
    draw_tree();
}

// Check if a given label is in the EXPAND array.
function is_in_expand(word) {
    var word2 = word.replace(/\?$/, "");
    for (var i=0; i<MAXIDX; i++) {
        if (word2 == EXPAND[i])
            return true;
    }
    return false;
}

// Check URL for expansion info.
function get_expand_from_url() {
    var node = get_parameter("node");
    if (node == null) return;

    for (var i=0; i<NUM_ALTS; i++)
        if (node == ALTS[i][0])
            node = ALTS[i][1];

    // Show full tree if can't find node in pruned tree.
    if (IMPORTANT_TREE != null &&
        !find_node(IMPORTANT_TREE, node, 0))
        IMPORTANT = 0;

    // Traverse tree to find this node.
    if (!find_node(FULL_TREE, node, 0)) {
        alert("Cannot find " + node + " in this tree.\n");
        return;
    }

    // Copy list of nodes that need to be expanded to get to node.
    var j = 0;
    for (var i=0; i<MAXIDX; i++)
        EXPAND[i] = "";
    for (var i=0; i<MAXIDX; i++)
        if (EXPAND2[i] != "")
            EXPAND[j++] = EXPAND2[i];

    // Tell draw_tree() to make this node look obnoxious.
    HIGHLIGHT = node;
}

// ----------------------------
//  Popup stuff.
// ----------------------------

var MAX_NUM_POPS = 100;
var POPS_X1     = new Array(MAX_NUM_POPS);
var POPS_X2     = new Array(MAX_NUM_POPS);
var POPS_Y1     = new Array(MAX_NUM_POPS);
var POPS_Y2     = new Array(MAX_NUM_POPS);
var POPS_LABELS = new Array(MAX_NUM_POPS);
var POPS_LATINS = new Array(MAX_NUM_POPS);
var NUM_POPS;
var CUR_POP;
var DONE_RHS;

// This is called whenever the mouse is moved.
function mouse_moved(event, x, y) {

    // Look for inner-most box that the cursor is in.
    var best = -1;
    for (var i=0; i<NUM_POPS; i++)
        if (x >= POPS_X1[i] && x < POPS_X2[i] &&
            y >= POPS_Y1[i] && y < POPS_Y2[i])
            if (best < 0 || POPS_X1[i] > POPS_X1[best])
                best = i;

    // Show / change / move / hide popup as required.
    if (best < 0) {
        hide_popup("popup");
        hide_popup("box1");
        hide_popup("box2");
        hide_popup("box3");
        hide_popup("box4");
        CUR_POP = -1;
    } else {
        if (best != CUR_POP) {
            draw_popup(best);
            //fit_popup("popup", x+10, y+10);
            fit_popup("popup", POPS_X2[best]-10, y);
        }
        CUR_POP = best;
    }
}

// Create contents of popup.
function draw_popup(num) {
    var html = "";

    var latin = POPS_LABELS[num];
    var common = get_common(latin);
    if (common != "") {
        common = common.replace(/,.*/, "");
        common = common.replace(/ \(.*/, "");
             if (latin.match(/phyta(_|$)/))    common += " Division";
        else if (latin.match(/mycota(_|$)/))   common += " Division";
        else if (latin.match(/phyceae(_|$)/))  common += " Subdivision";
        else if (latin.match(/mycotina(_|$)/)) common += " Subdivision";
        else if (latin.match(/opsida(_|$)/))   common += " Class";
        else if (latin.match(/mycetes(_|$)/))  common += " Class";
        else if (latin.match(/idae(_|$)/))     common += " Subclass";
        else if (latin.match(/iflorae(_|$)/))  common += " Superorder";
        else if (latin.match(/ales(_|$)/))     common += " Order";
        else if (latin.match(/aceae(_|$)/))    common += " Family";
        else if (latin.match(/oideae(_|$)/))   common += " Subfamily";
        else if (latin.match(/eae(_|$)/))      common += " Tribe";
        else if (latin.match(/inae(_|$)/))     common += " Subtribe";
        if (latin.match(/_s._str.$/)) common += " (strict sense)";
        if (latin.match(/_s._l.$/))   common += " (broad sense)";
    }

    var notes = "";
    for (var i=0; i<NUM_NOTES; i++) {
        if (NOTES[i][0] == latin)
            notes = NOTES[i][1];
    }

    if (common != "")
        html += "<center><nobr>&nbsp;<u><b>" + common +
            "</b></u>&nbsp;</nobr></center>";
    for (var i=0; i<POPS_LATINS[num][0]; i++)
        html += "<nobr>&nbsp;<font color='#B05018'>" +
            debar(POPS_LATINS[num][i+1]) +
            "</font>&nbsp;</nobr><br>";
    if (notes != "")
        html += "<center><nobr>&nbsp;<font size=-2 color='#C08060'><nobr>" + notes + "</nobr></font>&nbsp</nobr></center>";

    html =
        "<table bgcolor='#808080' cellspacing=1 cellpadding=0><tr><td>" +
        "<table bgcolor='#101010' cellspacing=0 cellpadding=3><tr><td>" +
        html
        "</table>" +
        "</table>";
    write_popup("popup", html);

    var x = POPS_X1[num] + 4;
    var w = POPS_X2[num] - x + 2;
    var y = POPS_Y1[num];
    var h = POPS_Y2[num] - y;

    var html = "<table width=" + w + " height=2 bgcolor='#FF4040' " +
        "cellspacing=0 cellpadding=0><tr><td></table>";
    write_popup("box1", html);
    show_popup("box1", x, y-2);

    var html = "<table width=" + w + " height=2 bgcolor='#FF4040' " +
        "cellspacing=0 cellpadding=0><tr><td></table>";
    write_popup("box2", html);
    show_popup("box2", x, y + h - 2);

    var html = "<table width=2 height=" + h + " bgcolor='#FF4040' " +
        "cellspacing=0 cellpadding=0><tr><td></table>";
    write_popup("box3", html);
    show_popup("box3", x, y);

    var html = "<table width=2 height=" + h + " bgcolor='#FF4040' " +
        "cellspacing=0 cellpadding=0><tr><td></table>";
    write_popup("box4", html);
    show_popup("box4", x + w - 2, y);
}

// Find location/size of all the boxes in the tree.
function locate_boxes() {

    // All calculations are offsets from top left of tree.
    var x1 = get_position("topleft");
    var x2 = get_position("topright");
    for (var i=0; i<NUM_POPS; i++) {
        POPS_X1[i] += x1.x - (isIE ? 10 : 0);
        POPS_X2[i]  = x2.x - (isIE ? 10 : 0);
        POPS_Y1[i] += x1.y + 8;
        POPS_Y2[i] += x1.y + 8;
    }

    // Start with popup hidden.
    CUR_POP = -1;
    hide_popup("popup");

    // Warp scrollbar to a better location if can't see tree / HIGHLIGHT.
    var win  = get_window_size();
    var xoff = get_window_x_offset();
    var yoff = get_window_y_offset();
    var bot  = get_position("bottom");
    var warp = yoff;

    // Window showing beyond end of document?
    if (yoff + win.h > bot.y + 25)
        warp = bot.y + 25 - win.h;

    // Can we see the blood-red highlighted leaf?
    if (HIGHLIGHT_Y >= 0  && (
        yoff > HIGHLIGHT_Y + x1.y + 8 - 18*3 ||
        yoff + win.h < HIGHLIGHT_Y + x1.y + 8 + 18*3
    ))
        warp = HIGHLIGHT_Y + x1.y + 8 - Math.floor(win.h/2);
    //alert("win: ["+yoff+" + "+win.h+"], bot: "+bot.y+", HY: "+HIGHLIGHT_Y+", warp: "+warp+".\n");

    // Tell window to change scroll.
    if (warp < 0) warp = 0;
    if (warp != yoff)
        window.scrollTo(xoff, warp)
}

// ----------------------------
//  Random other utilities.
// ----------------------------

// Get filename from links list.
function get_link(word) {
    for (var i=0; i<NUM_LINKS; i++)
        if (word == LINKS[i][0])
            return LINKS[i][1];
    return "";
}

// Convert "latin" to common name.
function get_common(word) {
    for (var i=0; i<NUM_COMMONS; i++)
        if (word == LATINS[i])
            return COMMONS[i].replace(/^\*/, "");
    return "";
}

// Is this an "important" node?
function is_important(word) {
    for (var i=0; i<NUM_COMMONS; i++)
        if (word == LATINS[i])
            return(COMMONS[i].match(/^\*/) ? true : false);
    return false;
}

// Go to parent tree.
function set_important(state) {
    IMPORTANT = state;
    draw_tree();
}

// Go to parent tree.
function goto_parent() {
    document.location.href = TOP_LINK;
}


