/
CDC-1.2b/
CDC-1.2b/src/
parent $help_root
parent $user_interfaces
object $help_ui

var $root dbref 'help_ui
var $root child_index 0
var $root fertile 1
var $root manager $help_ui
var $root owned [$help_ui]
var $root owners [$help_ui]
var $root writable []
var $root readable ['parameters, 'methods, 'code]
var $root inited 1
var $help_ui current_node 0
var $help_ui help_evaluator 0
var $help_ui help_path 0
var $has_commands commands [["@help *", 'help_cmd], ["@help-link *", 'help_link_cmd]]
var $has_commands shortcuts [["?*", 'help_link_cmd, ["@help-link", 1]]]
var $old_command_environment verb_cache #[]
var $old_command_environment command_cache [["@help *", 'help_cmd], ["@help-link *", 'help_link_cmd]]
var $old_command_environment shortcuts_cache [["?*", 'help_link_cmd, ["@help-link", 1]]]
var $help_ui last_visited []
var $has_messages message_info #[]
var $has_messages messages 0

method help_link_cmd
    arg cmd, what;
    var way, p, node;
    
    (> .perms(sender(), 'this) <);
    catch ~nodenf {
        if (!what) {
            // stick with the current node
        } else if (((what[1]) == "<") || ((what[1]) == ">")) {
            (> ._navigate_node_history(what) <);
        } else if ((what[1]) == "?") {
            return ._help_node_history();
        } else {
            (> ._navigate_node(what) <);
        }
    } with handler {
        .tell((traceback()[1])[2]);
        return;
    }
    .build_help_page();
.

method init_help_ui
    (> .perms(caller(), $root) <);
    current_node = $help.default_help_node();
    last_visited = #[['pos, 1], ['nodes, [current_node]]];
.

method current_node
    return current_node;
.

method add_link
    .perms(sender(), 'manager);
.

method help_cmd
    arg cmd, args;
    var cnode, n, nodes;
    
    (> .perms(sender(), 'this) <);
    args = args.explode();
    if (args) {
        cnode = (| ._find_help_node(args[1], 'index) |);
        if (!cnode)
            return;
        for n in [2 .. listlen(args)] {
            cnode = (| ._find_help_node(args[n], 'downnodes) |);
            if (!cnode)
                return;
        }
    } else {
        cnode = $help.default_help_node();
    }
    .set_help_node(cnode, 'new);
    .build_help_page();
.

method build_node_data
    arg node;
    var vars, message;
    
    vars = $root_evaluator.fix_values(#[["downnodes", node.downnodes()], ["upnodes", node.upnodes()], ["title", node.title()]]);
    vars = dict_add(vars, "body", (node.body()).ctext());
    message = .eval_message("help.format", vars);
    return message;
.

method eval_body
    return body.eval_cml(#[['evaluator, $help_evaluator], ['time, 'pre]]);
.

method build_help_page
    var out, len, clen, line, n;
    
    (> .perms(sender(), 'this) <);
    n = current_node;
    len = ((.linelen()) % 2) ? (.linelen()) - 1 | (.linelen());
    .tell(((" " + (n.name())) + " ").center(len, "-"));
    .tell((n.body()).eval_ctext());
    .tell(pad("", len, "-"));
    if (n.upnodes())
        .tell("Up-nodes:   " + (((n.upnodes()).map('name)).to_english()));
    if (n.downnodes())
        .tell("Down-nodes: " + (((n.downnodes()).map('name)).to_english()));
.

method _find_help_node
    arg what, type;
    var pos, cnode;
    
    (> .perms(sender(), 'this) <);
    switch (type) {
        case 'index:
            cnode = $help_index.find_help_node(what);
            if (cnode)
                return cnode;
            else
                throw(~nodenf, ("Unable to find help on \"" + what) + "\".");
        case 'link:
            if (what in dict_keys(current_node.links()))
                return (current_node.links())[what];
            else
                throw(~nodenf, ("No node link \"" + what) + "\" found on current node.");
        default:
            if (current_node.(type)()) {
                if (strlen(what) == 1) {
                    return current_node.(type)()[1];
                } else {
                    what = substr(what, 2);
                    pos = what in (current_node.(type)().map('name));
                    if (pos)
                        return current_node.(type)()[pos];
                    else
                        throw(~nodenf, "No downnode named " + what);
                }
            } else {
                throw(~nodenf, ((("No " + tostr(type)) + " defined from node ") + (current_node.name())) + ".");
            }
    }
.

method _back_help_node
    var p;
    
    (> .perms(sender(), 'this) <);
    p = (last_visited['pos]) - 1;
    if (p) {
        last_visited.add('pos, p);
        return (last_visited['nodes])[p];
    } else {
        .tell("There are no more help nodes to step back to, in your history.");
        throw(~stop, "", 'no_traceback);
    }
.

method _forward_help_node
    var p;
    
    (> .perms(sender(), 'this) <);
    p = (last_visited['pos]) + 1;
    if (p <= listlen(last_visited['nodes])) {
        last_visited.add('pos, p);
        return (last_visited['nodes])[p];
    } else {
        .tell("There are no more help nodes to step forward to, in your history.");
        throw(~stop, "", 'no_traceback);
    }
.

method set_help_node
    arg node, type;
    var h, p, ns;
    
    // god this is getting UGLY, but I can't think right now (sigh)
    (> .perms(sender(), 'this) <);
    current_node = node;
    ns = last_visited['nodes];
    p = last_visited['pos];
    switch (type) {
        case 'back, 'forward:
        case 'new:
            // hardcode the history cap for now
            if (listlen(ns) >= 10)
                ns = delete(h, 1);
            ns = ns.union([node]);
            last_visited = last_visited.add('nodes, ns);
    }
    last_visited = last_visited.add('pos, node in ns);
.

method _navigate_node_history
    arg what;
    var way, p;
    
    (> .perms(sender(), 'this) <);
    way = ((what[1]) == "<") ? 'back | 'forward;
    if (strlen(what) == 1) {
        .set_help_node(.(tosym(("_" + tostr(way)) + "_help_node"))(), way);
    } else {
        what = substr(what, 2);
        p = what in ((last_visited['nodes]).map('name));
        if (p)
            .set_help_node((last_visited['nodes])[p], way);
        else
            throw(~nodenf, ("There is no node \"" + what) + "\" in your history.");
    }
.

method _help_node_history
    var n, ns, p, l;
    
    (> .perms(sender(), 'this) <);
    ns = last_visited['nodes];
    p = last_visited['pos];
    .tell("Help node history:");
    for n in [1 .. listlen(ns)] {
        if (p == n)
            l = "=> ";
        else
            l = "   ";
        .tell(((l + pad(tostr(n) + ":", -2)) + " ") + ((ns[n]).name()));
    }
    .tell("--");
.

method _navigate_node
    arg what;
    var n, ns, p;
    
    (> .perms(sender(), 'this) <);
    catch ~nodenf {
        n = ._find_help_node(what, 'link);
    } with handler {
        ns = (current_node.upnodes()) + (current_node.downnodes());
        if (!ns)
            rethrow(error());
        p = what in (ns.map('name));
        if (!p)
            throw(~nodenf, ("No node found by the name \"" + what) + "\".");
        n = ns[p];
    }
    .set_help_node(n, 'new);
.