#!/usr/bin/perl
#use Mooix::Thing;
#use Mooix::Root;
#use Mooix::Verb;

my $last_collide;
sub collide {
	my $this=shift;
	
	# Pick an object, and collide with it.
	# This behavior should probably be tunable
	# with a stupidity field..
	my @objs=grep { $_ != $last_collide && $_ != $this &&
		        ! $_->hidden }
		 $this->location->contents->list;
	my $obj=$objs[rand @objs];
	$last_collide=$obj;
					
	# Lock the object to collide with, and make
	# sure it's still present.
	return 1 unless $obj;
	my $objlock=$obj->getlock(LOCK_SH);
	if ($obj->location == $this->location) {
		# Lock and make sure the flying was not interrupted.
		my $lock=$this->getlock(LOCK_EX);
		return unless $this->flying;
		$this->msg("collide", obj => $obj);
	}

	return 1;
}

sub takeexit {
	my $this=shift;
	# Pick an exit, and try to fly through it.
	my $anexit=$Mooix::Root->concrete->exit;
	my @exits=grep { $_->isa($anexit) } $this->location->contents->list;
	my $exit=$exits[rand $exits];

	# Lock the exit, and make sure it's still present.
	return 1 unless $exit;
	my $exitlock=$exit->getlock(LOCK_SH);
	if ($exit->location == $this->location) {
		# Lock and make sure the flying was not interrupted.
		my $lock=$this->getlock(LOCK_EX);
		return unless $this->flying;
		
		# To take the exit, run its go_verb. Pass noautoopen
		# to avoid opening doors.
		my $ret=$exit->go_verb(avatar => $this, noautoopen => 1,
		                       avatar_is_locked => 1);
		# Taking the exit unsets flying, so reset it.
		$this->flying(1);
	}

	return 1;
}
												
run sub {
	my $this=shift;
	
	# Lock the bird while it panics.
	my $lock=$this->getlock(LOCK_EX);

	# If in a container, try to move all the way out to the main room.
	if ($this->location && $this->location->location) {
		my $to=$this->location;
		# TODO really need to lock the containers all closed
		# as I go, to prevent races with the containers closing
		while ($to->location && ! $to->closed) {
			$to=$to->location;
		}
		$this->physics->move(object => $this, to => $to);
	}
	
	$this->msg("panic", @_);

	if ($this->location->location) {
		# If the bird was marked as flying when panic was called,
		# but is in some container it cannot get out of, then it
		# cannot fly around. Just land it.
		if ($this->flying) {
			close $lock; # land locks it
			$this->land(quiet => 1);
		}
	}
	else {
		if (! $this->flying) {
			$this->fly;
		}
		# Drop the lock while sleeping, to let the panic be
		# interrupted.
		close $lock;
		
		if (rand() > 0.5) {
			my $obj;
			for (1..rand(4)) {
				select(undef, undef, undef, rand(1) + 0.2);
				if (rand > 0.5) {
					return unless collide($this);
				}
				else {
					return unless takeexit($this);
				}
			}
		}
		select(undef, undef, undef, rand(2) + 1);
		$this->land;
	}
}
