/
CDC-1.2b/
CDC-1.2b/src/
parent $help_root
parent $named
parent $tree
object $help_node

var $root dbref 'help_node
var $root child_index 15
var $root fertile 0
var $root manager $help_node
var $root owned [$help_node]
var $root owners [$help_node]
var $root writable []
var $root readable ['parameters, 'methods, 'code]
var $root inited 1
var $named name ['uniq, "help_node"]
var $named name_aliases []
var $help_node links 0
var $help_node title 0
var $help_node body 0
var $help_node linked []
var $help_node indices 0
var $help_node linked_by []
var $help_node upnodes []
var $help_node downnodes []
var $tree parents_by_tree #[]
var $tree children_by_tree #[]

method init_help_node
    linked_by = [];
    links = #[];
    
    // title = "";
    body = $ctext_class.new([]);
    
    // upnodes = [];
    // downnodes = [];
.

method uninit_help_node
    var obj;
    
    for obj in (linked)
        (| obj.node_going_away() |);
    for obj in (indices)
        (| obj.node_going_away() |);
    indices = [];
    linked = [];
    links = #[];
    title = "";
    body = [];
.

method index_going_away
    (> .perms(caller(), $help_index) <);
    
    // ack, it is going away!  Not good, but we cannot do anything about it
    .del_index(sender());
.

method set_body
    arg new_body;
    var new_body, anchors, a, old_anchors;
    
    //Compile a string into help ctext
    new_body = $help_evaluator.compile_cml(new_body);
    body = $ctext_class.new(new_body['result]);
    
    // If old anchors aren't in the new body, delete them.
    old_anchors = links;
    catch ~keynf {
        anchors = new_body['anchors];
    } with handler {
        anchors = #[];
    }
    
    // delete every anchor not found in the new anchors.
    for a in (dict_keys(old_anchors)) {
        if (!(a in dict_keys(anchors)))
            (| (old_anchors[a])._del_link() |);
    }
    
    //Initialize new anchors not in old_anchors
    for a in (dict_keys(anchors)) {
        if (!(a in dict_keys(old_anchors))) {
            if (!((anchors[a]).accept_link()))
                anchors = dict_del(anchors, a);
        }
    }
    links = anchors;
.

method body
    return body;
.

method links
    return links;
.

method add_link
    arg key, node;
    
    (> .perms(sender(), 'manager) <);
    links = dict_add(links, key, node);
.

method del_link
    arg name;
    
    .perms(sender(), 'manager);
    if (name in dict_keys(links))
        links = dict_del(links, name);
.

method node_going_away
    var node;
    
    (> .perms(caller(), $help_node) <);
    node = sender();
    
    // do something intelligent with the text body as well
    links = dict_del(links, node);
.

method eval_body
    return body.eval_ctext(#[['time, 'pre]]);
.

method add_index
    arg index;
    
    (> .perms(caller(), 'this) <);
    indices = setadd(indices, index);
.

method del_index
    arg index;
    
    (> .perms(caller(), 'this) <);
    indices = setremove(indices, index);
    
    // There can be unindexed topics.
    // if (!indices)
    //  .add_index($help_index_general);
.

method generate_body_as
    arg type;
    
    switch (type) {
        case "text/plain":
            //  $help_evaluator.eval_cml(  hsm, this isn't right...
        case "text/html":
    }
.

method set_title
    arg new_title;
    
    .perms(sender(), 'manager);
    title = new_title;
.

method title
    return title;
.

method accept_link
    linked_by = [@linked_by, sender()];
    return 1;
.

method set_upnode
    arg upnode;
    
    .perms(sender(), 'manager);
    if (upnode.accept_link("downnode"))
        links = dict_add(links, "upnode", upnode);
    else
        throw(~refuse, "Parent refuses to accept link");
.

method downnodes
    return (| .children_by_tree('help) |) || [];
.

method upnodes
    return (| .parents_by_tree('help) |) || [];
.

method _del_downnode
    if (sender() in downnodes)
        downnodes = delete(downnodes, sender() in downnodes);
.

method _del_link
    //sender no longer links to us.
    if (sender() in linked_by)
        linked_by = delete(linked_by, sender() in linked_by);
.

method _del_upnode
    if (sender() in upnodes)
        upnodes = delete(upnodes, sender() in upnodes);
.

method _set_link
    arg node, name;
    var linked_as;
    
    //Ask node if we can link to it.
    linked_as = node.accept_link(name);
    if (linked_as) {
        if (name in dict_keys(links))
            (links[name])._del_link(back_links[node]);
        links = dict_add(links, name, node);
        back_links = dict_add(back_links, linked_as);
    } else {
        throw(~refuse, "Node refused link");
    }
.

method accept_as_child
    // The sender wants to be our child.
    return 1;
.

method accept_as_parent
    // The sender wants to know if we will accept it as our parent.
    return 1;
.

method accept_upnode
    if (!(sender() in upnodes))
        upnodes = [@upnodes, sender()];
    return 1;
.

method add_downnode
    arg downnode;
    
    .perms(sender(), 'manager);
    .add_child_to_tree('help, downnode);
.

method add_upnode
    arg upnode;
    
    .perms(sender(), 'manager);
    .add_parent_to_tree('help, upnode);
.

method del_downnode
    arg node;
    
    .perms(sender(), 'writers);
    .remove_parent_from_tree('help, node);
.

method del_upnode
    arg node;
    
    .perms(sender(), 'writers);
    .del_parent_from_tree('help, node);
.

method delete_all
    var l;
    
    // delete all links to and from this node.
    if ("upnodes" in dict_keys(links)) {
        for l in (links["upnodes"])
            l._del_downnode();
        links = dict_del(links, "upnodes");
    }
    if ("downnodes" in dict_keys(links)) {
        for l in (links["downnodes"])
            l._del_upnode();
        links = dict_del(links, "downnodes");
    }
    for l in (dict_keys(links))
        l._del_link();
.

method accept_downnode
    if (!(sender() in downnodes))
        downnodes = [@downnodes, sender()];
    return 1;
.

method downnode_names
    var output, t;
    
    output = [];
    for t in (.downnodes())
        output = [@output, t.title()];
    return output;
.

method make_downnode
    arg name;
    var new;
    
    //make a new help node that is a downnode of this node.
    new = $help_node.spawn();
    new.set_name(name);
    .add_downnode(new);
    new.add_upnode(this());
.