package MModules;
use strict;

use vars qw(
  @ISA @EXPORT_OK
  %ModuleSources
  $ModuleEvalContext
  $ModuleEvalName
);

require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(
  $ModuleEvalContext
);

use Carp;
use MCoreTools;
use File::Path;

sub load_modules {
  my ($class) = @_;
  local *MODDIR;
  opendir MODDIR, "modules" or die $!;
  while (defined (local $_ = readdir MODDIR)) {
    next unless /^(.*)\.mod$/;
    $class->load_module($1);
    #MConnection->all_idle;
  }
  closedir MODDIR;
}

sub load_module {
  my ($self, $tname) = @_;

  $tname =~ /^([\w!]+)$/ or croak "Bad module name '$tname' passed to load_module";
  my $name = $1;
  
  my $path = "$::Config{mod_path}/$name.mod";
  my $filepath = rfile($path);
  my $fh = IO::File->new($filepath) or do {
    mudlog("$path - module file not found");
    return;
  };
  
  mudlog "Loading module '$name'...";
  $fh->untaint; # Safe to eval code stored on local disk, and the file path
                # has been checked.
  my $code = qq{package MModules::ModuleContext; use MCoreTools; \n#line 1 "$filepath"\n};
  $code .= <$fh> until $fh->eof;
  close $fh;
  
  # For some reason, eval() was modifying the passed string; therefore,
  # we make a copy.
  my $ccopy = $code;
  local $ModuleEvalContext = 'load';
  local $ModuleEvalName = $name;
  eval $code;
  if ($@) {
    return if $@ =~ "module load failed";
    mudlog "Error in loading $ModuleEvalName:\n$@";
  } else {
    $ModuleSources{$name} = $ccopy;
  }
}

sub unload_module {
  my ($self, $tname) = @_;

  $tname =~ /^(\w+)$/ or croak "Bad module name '$tname' passed to unload_module";
  my $name = $1;
  
  my $path = $::Config{mod_path} . '/' . $name;

  return unless exists $ModuleSources{$name};
  mudlog "Unloading module '$name'...";
  local $ModuleEvalContext = 'unload';
  local $ModuleEvalName = $name;
  eval $ModuleSources{$name};
  die $@ if $@;
  delete $ModuleSources{$name};
}

sub loaded {
  my ($self, $name) = @_;

  return exists $ModuleSources{$name};
}

1;
