/
CDC-1.2b/
CDC-1.2b/src/
parent $utilities
object $tree

var $root dbref 'tree
var $root child_index 2
var $root fertile 1
var $root manager $tree
var $root owned [$tree]
var $root owners [$]
var $root writable []
var $root readable ['parameters, 'methods, 'code]
var $root inited 1
var $tree parents_by_tree 0
var $tree children_by_tree 0

method add_as_child
    arg tree;
    
    if (!children_by_tree)
        children_by_tree = #[];
    children_by_tree = children_by_tree.add_elem(tree, sender());
    return 1;
.

method add_as_parent
    arg tree;
    
    if (!parents_by_tree)
        parents_by_tree = #[];
    parents_by_tree = parents_by_tree.add_elem(tree, sender());
    return 1;
.

method add_child_to_tree
    arg tree, child;
    
    .perms(sender(), 'writers);
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .add_child(child);
    if (type(child) != 'dbref)
        throw(~type, "child should be given as a dbref.");
    if (child in ((| children_by_tree[tree] |) || []))
        throw(~type, ((child.dbref()) + " is already a child in tree ") + tree);
    if (parent in (.ancestors_by_tree(tree)))
        throw(~type, ((parent.dbref()) + " is already an ancestor in tree ") + tree);
    if (!(child.add_as_child(tree)))
        throw(~refuse, "child refuses to be child.");
    children_by_tree = children_by_tree.add_elem(tree, child);
.

method add_parent_to_tree
    arg tree, parent;
    
    .perms(sender(), 'writers);
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .add_parent(parent);
    if (type(parent) != 'dbref)
        throw(~type, "parent should be given as a dbref.");
    if (parent in ((| parents_by_tree[tree] |) || []))
        throw(~type, ((parent.dbref()) + " is already a parent in tree ") + tree);
    catch ~tree {
        if (parent in (.ancestors_by_tree(tree)))
            throw(~type, ((parent.dbref()) + " is already an ancestor in tree ") + tree);
    }
    if (!(parent.add_as_child(tree)))
        throw(~refuse, "parent refuses to be parent.");
    parents_by_tree = parents_by_tree.add_elem(tree, parent);
.

method children_by_tree
    arg [tree];
    
    if (tree) {
        if ((tree[1]) == 'inheritance)
            return .children();
        catch ~keynf {
            return children_by_tree[tree[1]];
        } with handler {
            throw(~treenf, "No children in tree" + tostr(tree[1]));
        }
    } else {
        return children_by_tree;
    }
.

method ancestors_by_tree
    arg tree;
    var a, par, anc;
    
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .ancestors();
    if (!(tree in dict_keys(parents_by_tree)))
        throw(~tree, "not part of tree " + tostr(tree));
    par = parents_by_tree[tree];
    anc = [];
    while (par) {
        anc = setadd(anc, par[1]);
        par = [@par, @(par[1]).parents_by_tree(tree)];
    }
    return anc;
.

method del_child_from_tree
    arg tree, child;
    
    .perms(sender(), 'writers);
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .del_child(child);
    if (type(child) != 'dbref)
        throw(~type, "child should be given as a dbref.");
    if (!(child in ((| children_by_tree[tree] |) || [])))
        throw(~type, ((child.dbref()) + " is not a child in tree ") + tostr(tree));
    child.del_as_parent(tree);
    children_by_tree = children_by_tree.del_elem(tree, child);
.

method del_parent_from_tree
    arg tree, parent;
    
    .perms(sender(), 'writers);
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .del_parent(parent);
    if (type(parent) != 'dbref)
        throw(~type, "parent should be given as a dbref.");
    if (!(parent in ((| parents_by_tree[tree] |) || [])))
        throw(~type, ((parent.dbref()) + " is not a parent in tree ") + tostr(tree));
    parent.del_as_child(tree);
    parents_by_tree = parents_by_tree.del_elem(tree, parent);
.

method parents_by_tree
    arg [tree];
    
    if (tree) {
        if ((tree[1]) == 'inheritance)
            return .parents();
        catch ~keynf, ~type {
            return parents_by_tree[tree[1]];
        } with handler {
            throw(~tree, "Not parents in tree " + tostr(tree[1]));
        }
    } else {
        return parents_by_tree;
    }
.

method descendents_by_tree
    arg tree;
    var a, par, anc;
    
    if (type(tree) != 'symbol)
        throw(~type, "tree should be given as a symbol.");
    if (tree == 'inheritance)
        return .descendents();
    if (!(tree in dict_keys(children_by_tree)))
        throw(~tree, "not part of tree " + tostr(tree));
    par = children_by_tree[tree];
    anc = [];
    while (par) {
        anc = setadd(anc, par[1]);
        par = [@par, @(par[1]).children_by_tree(tree)];
    }
    return anc;
.

method init_tree
    parents_by_tree = #[];
    children_by_tree = #[];
.

method uninit_tree
    parents_by_tree = 0;
    children_by_tree = 0;
.

method del_as_child
    arg tree;
    
    .debug(children_by_tree, tree);
    children_by_tree = children_by_tree.del_elem(tree, sender());
.

method del_as_parent
    arg tree;
    
    parents_by_tree = parents_by_tree.del_elem(tree, sender());
.