+ my $parent = shift;
+ my @out;
+ foreach my $rcall (@{$parent->{nodes}}) {
+ my $r = get($rcall);
+ push @out, $r->del($parent, $parent->{call}, @_) if $r;
+ }
+ return @out;
+}
+
+sub _del_users
+{
+ my $self = shift;
+ for (@{$self->{users}}) {
+ my $ref = Route::User::get($_);
+ $ref->del($self) if $ref;
+ }
+ $self->{users} = [];
+}
+
+# add a user to this node
+sub add_user
+{
+ my $self = shift;
+ my $ucall = shift;
+
+ confess "Trying to add NULL User call to routing tables" unless $ucall;
+
+ my $uref = Route::User::get($ucall);
+ my @out;
+ if ($uref) {
+ push @out, $uref->addparent($self);
+ } else {
+ $uref = Route::User->new($ucall, $self->{call}, @_);
+ push @out, $uref;
+ }
+ $self->_adduser($uref);
+ $self->{usercount} = scalar @{$self->{users}};
+
+ return @out;
+}
+
+# delete a user from this node
+sub del_user
+{
+ my $self = shift;
+ my $ref = shift;
+ my @out;
+
+ if ($ref) {
+ @out = $self->_deluser($ref);
+ $ref->del($self);
+ } else {
+ confess "tried to delete non-existant $ref->{call} from $self->{call}";
+ }
+ $self->{usercount} = scalar @{$self->{users}};
+ return @out;
+}
+
+sub usercount
+{
+ my $self = shift;
+ if (@_ && @{$self->{users}} == 0) {
+ $self->{usercount} = shift;
+ }
+ return $self->{usercount};
+}
+
+sub users
+{
+ my $self = shift;
+ return @{$self->{users}};
+}
+
+sub nodes
+{
+ my $self = shift;
+ return @{$self->{nodes}};
+}
+
+sub parents
+{
+ my $self = shift;
+ return @{$self->{parent}};
+}
+
+sub has_user
+{
+ my $self = shift;
+ return $self->_haslist('users', shift);
+}
+
+sub has_node
+{
+ my $self = shift;
+ return $self->_haslist('nodes', shift);
+}
+
+sub has_parent
+{
+ my $self = shift;
+ return $self->_haslist('parent', shift);
+}
+
+
+sub rnodes
+{
+ my $self = shift;
+ my @out;
+ foreach my $call (@{$self->{nodes}}) {
+ next if grep $call eq $_, @_;
+ push @out, $call;
+ my $r = get($call);
+ push @out, $r->rnodes($call, @_) if $r;
+ }
+ return @out;
+}
+
+# return the differences in nodes between what we currently have and
+# the list proffered. Returns two refs one to a list of nodes to remove and
+# the other a list of nodes to add
+#
+# input is a list of callsigns (not refs)
+sub diff_nodes
+{
+ my $self = shift;
+ my $in = ref $_[0] ? shift : \@_;
+ my %del = map {($_, 1)} nodes($self);
+ my %in = map {($_, 1)} @$in;
+
+ # remove all the calls that are in both lists
+ for (@$in) {
+ delete $in{$_} if delete $del{$_};
+ }
+ return ([keys %del], [keys %in]);
+}
+
+# same as above but for users
+sub diff_users
+{
+ my $self = shift;
+ my $in = ref $_[0] ? shift : \@_;
+ my %del = map {($_, 1)} users($self);
+ my %in = map {($_, 1)} @$in;
+
+ # remove all the calls that are in both lists
+ for (@$in) {
+ delete $in{$_} if delete $del{$_};
+ }
+ return ([keys %del], [keys %in]);