#!/usr/bin/perl
#use Fcntl q{:flock};
#use Mooix::Thing;
#use Mooix::Root;
run sub {
	my $this=shift;
	%_=@_;
	my $obj=$_{direct_object};
	my $newparent=$_{indirect_object};
	
	# The admin's reparent verb calls this one with avatar_reparent_ok
	# set, to allow reparents of avatars. By default it's not allowed.
	if ($_{avatar_reparent_ok} != 1) {
		if ($obj == $this || $obj->isa($Mooix::Root->abstract->avatar)) {
			fail "You cannot reparent yourself or other avatars.";
		}

		# This is just paranioa.
		if ($newparent->isa($Mooix::Root->abstract->avatar)) {
			fail "You can't do that.";
		}
	}
	
	# Need to protect against parent loops. Here's the strategy:
	#
	#  Start at the newparent, and walk its parent tree up to the top.
	#  
	#  If the obj is found, a loop would be created so abort.
	#  
	#  Keep track of seen objects, to detect existing loops.
	#  
	#  Lock objects exclusively at each step; this prevents races with
	#  another instance of this method being run on the other object.
	#  Such a race would have worked like this:
	#
	#    1. request reparent of object a to object b
	#    2. request reparent of object b to object a (simulantaneously)
	#    3. first reparent concludes that b is not a child of a
	#    < here the locking causes second reparent to pause, and avoids
	#    the race..>
	#    4. second reparent concludes that a is not a child of b
	#    5. forced pause; race is here
	#    6. first reparent reparents a to b
	#    7. second reparent reparents b to a; loop created
	my @locks;
	my %seenobjs;
	my $parent=$newparent;
	while (ref $parent) {
		if ($parent == $obj) {
			fail "That would create a parent loop!";
		}
		if ($seenobjs{$parent->index}) {
			fail "There seems to be a parent loop!";
		}
		$seenobjs{$parent->index}=1;
		push @locks, $parent->getlock(LOCK_EX);
		$parent=$parent->parent;
	}
	
	if ($obj->parent($newparent) == $newparent) {
		# Do message before init, as init may decide to output some
		# messages.
		$obj->msg("reparent", %_, parent => $newparent);
		# Reinit object.
		$obj->init;
	}
	else {
		fail "You cannot reparent that.";
	}
}
