#!/usr/bin/perl
#use Mooix::Thing;
#use Mooix::Root;
#use Fcntl q{:flock};
use Mooix::CallStack;

# I'd like to use Time::Duration, but I don't haveta.
eval "use Time::Duration";
if ($@) {
	*::ago = sub { return shift()." seconds ago" };
	*::duration = sub { return shift()." seconds" };
}

run sub {
	my $this=shift;
	%_=@_;
	my $session = $_{session} or $this->usage("bad session");
	my $quiet = $_{quiet};

	# This method runs stackless, and it only allows the sessionmanager
	# to ask it to log in, via its login method.
	if (! Mooix::CallStack::calledby($Mooix::Root->system->sessionmanager, 'login', 1)) {
		$this->croak("only sessionmanager->login can call this method");
	}
	
	# The nologin field can prevent logins.
	my ($nologin, $why)=$this->nologin;
	if ($nologin > time) {
		$session->write($why) if length $why;
		$session->write("You cannot log in for another ".
			        duration($nologin - time, 1). # be vague
				"."); # be vague
		return;
	}
	elsif ($nologin < 0) {
		$session->write($why) if length $why;
		$session->write("You cannot log in!");
		return;
	}
	
	# Print last login banner.
	my $logintime=time();
	if (! $quiet && $this->lastlogin) {
		my $logtime = (stat($this->fieldfile("lastlogin")))[9];
		$session->write("Your last login was ".ago(time - $logtime).
		                " from ".$this->lastlogin.".");
		$session->write(""); # blank line
	}
	
	# Put the hostname logged in from into the lastlogin file.
	$this->lastlogin($_{hostname}) if length $_{hostname};
	
	# Add the session to our list.
	$this->sessions->add(object => $session);
	
	my $hp=$this->hitpoints;
	if ($hp <= $this->minhitpoints) {
		# The avatar is dead, but no longer locked out.
		# Bring back to life.
		$this->resurrect;
		$this->sleeping(0); # don't show them waking up below
		$hp = $this->hitpoints;
	}
	elsif ($hp <= 0) {
		# Avatar may still be unconcious, or they may have healed
		# in their "sleep".
		$this->hp_regen;
		$hp = $this->hitpoints;
		if ($hp <= 0) {
			$session->write("You are unconscious.");
		}
	}
	
	# If there is no location, go home.
	my $needlook=1;
	if (! $this->location && $this->home) {
		$this->physics->move(object => $this, to => $this->home);
		$this->msg('arrive', skip => $this);
		$this->sleeping(0); # don't show them waking up below
		$needlook=0;
	}
	
	if ($this->location) {
		# If they are asleep, show them waking up. The sleeping
		# flag is used, rather then just counting the sessions to
		# see if someone is logged in, because session counting is
		# prone to races: if two sessions are created at the same
		# time, then both will see the other session, and not show
		# the avatar coming awake.
		#
		# Of course, if they are unconcious, whether they are
		# asleep or not doesn't matter, though the field is updated
		# anyway.
		my $lock=$this->getlock(LOCK_EX, "sleeping");
		if ($this->sleeping) {
			$this->sleeping(0);
			$this->msg('wake', avatar => $this) unless $quiet || $hp <= 0;
		}
		
		if ($hp > 0 && ! $quiet && $needlook) {
			# Autolook on login.
			$this->location->look_verb(avatar => $this,
				session => $session);
		}
	}
	
	return 1;
}
