package Mud::CoreTools;
use strict;
use Exporter;
use vars qw(@ISA @EXPORT $Root);

@ISA = qw(Exporter);
@EXPORT = qw(
  IS_MACOS
  mudlog
  carp cluck croak confess
  Object
);

use Cwd ();

=head1 Exported Symbols

=over 4

=cut

### Misc constants and functions ##########################################################################################

=item IS_MACOS

Constant that is true if we're running under "classic" Mac OS.

=cut

use constant IS_MACOS => $^O eq 'MacOS';

=item Object(TAG, KEY)

Returns a proxy for the object in the storage specified by TAG with the specified
access key.

=cut

sub Object { Mud::Storage->storage($_[0])->obj($_[1]) }

=item init_sub_package(PACK, SUB)

Not exported. This sets up the standard namespace for StorableSub compiled methods.

=cut

sub init_sub_package {
  my ($pack, $ssub) = @_;

  no strict 'refs';

  eval "package $pack; import " . __PACKAGE__;
  die $@ if $@;
}

### Logging ################################################################

=item mudlog(STR)

Sends STR to various log destinations, usually including a file on disk.
Adds the current date to the string.

=cut

sub mudlog ($) {
  # FIXME: implement real logging
  print STDERR "[Log] $_[0]\n";
}

### Carping ######################################

=item carp(), cluck(), croak(), confess()

Same as Carp:: functions of the same names.

=cut

use Carp; # can't specify list because Carp might not define cluck() depending on version
BEGIN {eval 'sub cluck {warn Carp::longmess @_}' unless defined &cluck}

###

=back

=head1 Methods

=over 4

=cut

### Initialization ##################################################

sub _sig ($$) {
  my ($sig, $val) = @_;
  $SIG{$sig} = $val if exists $SIG{$sig};
}

=item CM initialize(root => I<DIR>)

Sets up various global thingies. Currently:

=over 4

=item Sets the world root directory.

=item Installs signal handlers for these signals:

  __WARN__  Redirected to logging.
  PIPE      Ignored.
  HUP       Ignored.
  CHLD      wait()ed.
  INT       Shutdown.
  QUIT      Shutdown.
  TERM      Shutdown.
  USR1      Shutdown and restart.

=back

=cut

sub initialize {
  my ($class, %p) = @_;
  
  $p{root} =~ s/:$// if $^O eq 'MacOS';
  $Root = $p{root};

  # alright, what's the difference between SIGQUIT and SIGTERM? i
  # think the answer is SIGTERM means "system shutting down", whereas
  # SIGQUIT is a user request to "terminate now", and SIGINT just means
  # "stop what you're doing".
  #
  # is it legal to die() inside a signal handler?
  #
  # Ilya says return; at the end of a signal handler will reduce
  # the amount of things done in it by preventing a return value

  my $reaper;
  $reaper = sub { wait; $SIG{CHLD} = $reaper; return};

  $SIG{__WARN__} = sub {mudlog "WARNING: $_[0]" unless $_[0] =~ /Ambiguous use of .* resolved to .*\./};
  _sig PIPE => 'IGNORE';
  _sig HUP  => 'IGNORE';
  _sig CHLD => $reaper;
  _sig INT  => sub {$Mud::Scheduler::Quit = 'SIGINT'; return};
  _sig QUIT => sub {$Mud::Scheduler::Quit = 'SIGQUIT'; return};
  _sig TERM => sub {$Mud::Scheduler::Quit = 'SIGTERM'; return};
  _sig USR1 => sub {$Mud::Scheduler::Quit = 'restart'; return};
}

### Methods ##################################################

sub Root {$Root or confess "Mud::CoreTools not initialized yet";}

=back

=cut

__END__
