/
CDC-1.1/
parent $user
object $builder

var $root child_index 0
var $root owners [$builder]
var $root fertile 0
var $has_commands commands [["@par?ents *", 'parents_cmd], ["@dest?roy *", 'destroy_cmd], ["@child?ren|@kids *", 'children_cmd], ["@build *", 'build_cmd]]
var $has_commands shortcuts []
var $has_verbs verbs #[]
var $location contents []
var $located location $nowhere
var $user password "*"
var $user connected_at 0
var $user last_command_at 0
var $user connections []
var $root inited 1
var $root owned [$builder]
var $command_aliases command_aliases []
var $user modes #[]
var $gendered gender $gender_neuter
var $located obvious 1
var $described prose #[]
var $user prompt ""
var $root manager $builder
var $root writable [$builder]
var $root readable ['parameters, 'methods, 'code]
var $user parsers [$command_parser, $verb_parser]
var $user tell_traceback ['brief, 0]
var $user context #[]
var $root quota 75000
var $root dbref 'builder
var $named name ['uniq, "Generic Builder"]
var $named name_aliases []
var $user_data user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]

method dig_cmd
    arg com, exitname, prep, roomname;
    var egoing, ecoming, exits, here, there;
    
    here = .location();
    there = $nowhere;
    if (roomname && ((roomname[1]) == "$")) {
        // later check the $room_db setup
        there = (| $object.to_dbref(roomname) |);
        if (!there)
            $parse.tell_error(("No room found by the name \"" + roomname) + "\".");
    } else {
        there = ($room_utils.default_type()).spawn();
        there.set_name(roomname);
        .tell(("Created new room \"" + (there.namef('ref))) + "\".");
    }
    
    //
    exits = explode(exitname, "|");
    if (listlen(exits) == 0)
        $parse.tell_error("No exits specified!");
    if (listlen(exits) > 1) {
        if (listlen(exits) > 2)
            $parse.tell_error("Invalid format, too many exits specified");
        ecoming = $exit.spawn();
        ecoming.set_name(exits[2]);
        catch any {
            ecoming.attach(there);
            ecoming.link(here);
            .tell(((("Linked " + (here.namef('ref))) + " to ") + (there.namef('ref))) + ".");
        } with handler {
            ecoming.destroy();
            .tell("Could not make exit from there to here: " + ((traceback()[1])[2]));
        }
    }
    egoing = $exit.spawn();
    egoing.set_name(exits[1]);
    catch any {
        egoing.attach(here);
        egoing.link(there);
        .tell(((("Linked " + (there.namef('ref))) + " to ") + (here.namef('ref))) + ".");
    } with handler {
        egoing.destroy();
        .tell("Couldn't make exit from here to there: " + ((traceback()[1])[2]));
        return;
    }
    .tell("Place successfully Created and Linked.");
.

method children_cmd
    arg verb, what;
    var line, kid, colx, col, kids, x;
    
    what = .match_env_nice(what);
    kids = what.children();
    if (!kids) {
        .tell(("Children of " + (what.namef('xref))) + ": ** None **");
    } else {
        col = (.linelen()) / 8;
        colx = col * 3;
        line = (listlen(kids) > 1) ? "Children" | "Child";
        .tell(((line + " of ") + (what.namef('ref))) + ":");
        line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
        .tell((line + pad("Size ", -col)) + "Manager");
        for kid in (kids) {
            line = " " + (kid.namef('xref));
            line = pad(line, colx + 2);
            line = line + pad(" " + ($object.see_perms(kid)), col - 2);
            line = line + pad(tostr(kid.size()) + " ", -col);
            line = line + pad($object.get_name(kid.manager(), 'namef, ['xref]), colx);
            .tell(line);
        }
    }
.

method parents_cmd
    arg verb, what;
    var line, par, colx, col, parents, x;
    
    what = .match_env_nice(what);
    parents = what.parents();
    col = (.linelen()) / 8;
    colx = col * 3;
    line = "Parent" + ((listlen(parents) > 1) ? "s" | "");
    .tell(((line + " of ") + (what.namef('ref))) + ":");
    line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
    .tell((line + pad("Size ", -col)) + "Manager");
    for par in (parents) {
        line = " " + (par.namef('xref));
        line = pad(line, colx + 2);
        line = line + pad(" " + ($object.see_perms(par)), col - 2);
        line = line + pad(tostr(par.size()) + " ", -col);
        line = line + pad($object.get_name(par.manager(), 'namef, ['xref]), colx);
        .tell(line);
    }
.

method destroy_cmd
    arg destroy, what;
    var syntax;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    syntax = "@destroy <object>";
    what = .match_env_nice(what, syntax);
    catch any {
        what.destroy();
        .tell("Destroyed.");
    } with handler {
        $parse.tell_error((traceback()[1])[2], syntax);
    }
.

method _build_ask_roomname
    arg name, there;
    var x, exit;
    
    .perms(sender(), 'this);
    name = (| $code.parse_name(@name) |);
    if (!name) {
        .tell("Invalid room name.");
        $builder._build_destroy_stuff(there, []);
    } else {
        there = ['new, ($places.place('default_new)).spawn()];
        (there[2]).set_name(name[1]);
        for x in (name[2])
            (there[2]).add_name_alias(x);
        .tell(("  Created place " + ((there[2]).namef('ref))) + ".");
        .prompt("Exit name: ", '_build_ask_exitname, there, []);
    }
.

method build_cmd
    arg cmd, str;
    var there, exit, x;
    
    .perms(sender(), 'this);
    if (!str) {
        .prompt("Name of new room: ", '_build_ask_roomname, []);
    } else if ("-aliases" in str) {
        .tell("Radial/Azimuth Coordinate shortcuts:");
        .tell(" Shortcut            Radial Azimuth");
        for x in ($places.coordinate_shortcuts())
            .tell(((" " + pad(x[1], 20)) + pad(tostr((x[2])[1]), 7)) + tostr((x[2])[2]));
    } else {
        str = explode(str);
        there = .match_env_nice(str[listlen(str)]);
        catch any {
            $places.is_place(there);
        } with handler {
            return .tell((traceback()[1])[2]);
        }
        .prompt("Exit Name: ", '_build_ask_exitname, ['old, there], []);
    }
.

method _build_destroy_stuff
    arg there, exits;
    var success, x;
    
    .perms(sender(), 'this);
    if (there && ((there[1]) == 'new)) {
        success = (| (there[2]).destroy() |);
        if (success)
            .tell("Destination room sucessfully destroyed.");
        else
            .tell("Unable to destroy destination room: " + ($data.unparse(there[2])));
    }
    for x in [1 .. listlen(exits)] {
        success = (| (exits[x]).destroy() |);
        if (success)
            .tell(("Exit " + tostr(x)) + " sucessfully destroyed.");
        else
            .tell("Unable to destroy exit: " + ($data.unparse(exits[x])));
    }
.

method _build_ask_exitname
    arg name, there, exits;
    var x, y;
    
    name = (| $code.parse_name(@name) |);
    if ((!name) && (!exits)) {
        .tell("Invalid exit name.");
        ._build_destroy_stuff(there, exits);
        return;
    } else if (name) {
        exits = [@exits, $exit.spawn()];
        y = listlen(exits);
        (exits[y]).set_name(name[1]);
        for x in (name[2])
            (exits[y]).set_name_alias(x);
        .tell(("  Created exit " + ((exits[y]).namef('ref))) + ".");
        if (y < 2)
            .prompt("Returning exit name: ", '_build_ask_exitname, there, exits);
        else
            .prompt("Coordinates (radial,azimuth): ", '_build_ask_coordinates, there, exits);
    } else {
        .prompt("Coordinates (radial,azimuth): ", '_build_ask_coordinates, there, exits);
    }
.

method _build_ask_coordinates
    arg coord, there, exits;
    var err, radial, azimuth;
    
    .perms(sender(), 'this);
    err = "Invalid coordinates.  You must use either radial/azimuth coordinates or use coordinate aliases (use @build -aliases to get a listing of aliases).";
    coord = coord[1];
    if (!coord) {
        .tell(err);
        ._build_destroy_stuff(there, exits);
        return;
    } else {
        catch ~coordnf, ~invcoord {
            if ($string.is_numeric(coord)) {
                coord = explode(coord, ",");
                if (listlen(coord) != 2) {
                    .tell(err + "  Seperate actual radial/azimuth coordinates by a comma.");
                    ._build_destroy_stuff(there, exits);
                    return;
                }
                radial = toint(coord[1]);
                azimuth = toint(coord[2]);
            } else {
                coord = $places.coordinates(coord);
                radial = coord[1];
                azimuth = coord[2];
            }
            $places.valid_coordinates(radial, azimuth);
        } with handler {
            .tell((traceback()[1])[2]);
            ._build_destroy_stuff(there, exits);
            return;
        }
        .tell(((("  Using coordinates: Radial: " + tostr(radial)) + " Azimuth: ") + tostr(azimuth)) + ".");
    }
    ._build_done(there, exits, [radial, azimuth]);
.

method _build_done
    arg there, exits, coord;
    var here, x;
    
    .perms(sender(), 'this);
    here = .location();
    catch any {
        (exits[1]).attach(here, there[2], @coord);
    } with handler {
        .tell("Unable to attach exit because: ");
        .tell((traceback()[1])[2]);
        ._build_destroy_stuff(there, exits);
    }
    
    // second exit
    if (listlen(exits) == 2) {
        catch any {
            (exits[2]).attach(there[2], here, @$places.invert_coordinates(@coord));
        } with handler {
            .tell("Unable to attach return exit because: ");
            .tell((traceback()[1])[2]);
            ._build_destroy_stuff([], [exits[2]]);
        }
    }
    .tell("Finished building extension.");
    .tell("Use `@prose` to set long and short prose descriptions.");
.