package Mud::Proxy;
use strict;
use Mud::CoreTools;
use vars qw($AutoloadCode $AUTOLOAD);

$AutoloadCode = <<'EOC';
#line 1 ProxyRedirector:~~NAME~~
sub ~~NAME~~ {
}
EOC

=head1 Description

Mud::Proxy implements proxies for persistent objects using Mud::Storage, which
may be serialized.

This is an abstract class. Use Mud::Proxy::Key instead.

=head1 Methods

=cut

###  #####################################

=item CM new()

Creates a new object.

=cut

sub new {
  my ($class) = @_;
  my $self = bless {}, $class;
  return $self;
}

=item IM proxy_real_obj()

For subclass implementation. Returns the real object for this proxy. Should
only be called internally.

=cut

=item IM proxy_exists()

For subclass implementation. Returns whether the object the proxy refers to
still exists:

  Return value  State of the proxy
  ------------- --------------------------
  undef         Will never again be valid
  0             May be valid in the future
  1             Currently valid

=cut

=item IM AUTOLOAD(...)

Passes all method calls on to the referenced object.

=cut

sub AUTOLOAD {

  # DANGER: if a method is called with $1 or friends as arguments, our regex
  # matching here is going to mess things up...so we copy the arg list and so
  # break the lvalueness - doing so is probably Good, anyway.
  my @args = @_;

  my ($method) = $AUTOLOAD =~ /::([^:]+)$/;
  my $self = $_[0];
  my $real = $self->proxy_real_obj;

  #print $real->identity_text . "->$method(@args[1..$#args])\n";

  if ($method =~ /^proxy_/) {
    croak "'$method' is not a proxy method for " . ref $self;

  } elsif (my $m_sub_obj = eval {$real->getAttribute('method', $method)}) {
    $m_sub_obj->sub->(@args);

  } else {
    # FIXME: should catch 'Can't locate object method ... via package...' exception and report object id
    my ($retval, @retval);
    {
      local $Carp::CarpLevel = $Carp::CarpLevel + 1;
      wantarray ? @retval = eval {$real->$method(@args[1..$#args])}
                : $retval = eval {$real->$method(@args[1..$#args])};
    }
    if ($@) {
      if ($@ =~ /^(?:# )?Can't locate object method "(.*)" via package "(.*)"/s) {
        croak qq{Can't locate object method "$1" on object } . $real->identity_text;
      } else {
        die $@;
      }
    }
    return wantarray ? @retval : $retval;
  }
}
sub DESTROY {} # prevent proxy passing


# FIXME: document this
sub proxy_is {1}
sub UNIVERSAL::proxy_is {0}

###

=back

=cut

1;
__END__
