package Data::All::Base;

#   A base Spiffy module for all of Data::All

use strict;
no warnings;            #   Perl will complain about attribute being redefined

use Symbol;
use Spiffy '-base';
use Data::Dumper;

our $VERSION = 1.0;
our @EXPORT = qw(new internal attribute populate Dumper error);

sub internal;
internal 'ERROR';

sub error
{
    my ($self) = @_;
    
    return $self->__ERROR();
}

sub new
#   Bypass Spiffy's new, so we can call init()
{
    my $class = shift;
    
    my $self = bless Symbol::gensym(), $class;
    my ($args) = $self->parse_arguments(@_);
    tie *$self, $self if $args->{-tie};
    $self->use_lock(1) if $args->{-lock};
    
    return ($self->can('init'))
        ? $self->init(@_)
        : $self;
}



sub populate 
{
    my ($self, $args) = @_;

    for my $a (keys %{ $args })
    {
        warn(0, "No attribute method for $a"), next 
            unless $self->can($a);
        #warn 9, "Running $a"; 
        $self->$a($args->{$a});
    }
}

sub attribute {
    my $package = caller;
    my ($attribute, $default) = @_;
    no strict 'refs';
    return if defined &{"${package}::$attribute"};
    *{"${package}::$attribute"} =
      sub {
          my $self = shift;
          unless (exists *$self->{$attribute}) {
              *$self->{$attribute} = 
                ref($default) eq 'ARRAY' ? [] :
                ref($default) eq 'HASH' ? {} : 
                $default;
          }
          return *$self->{$attribute} unless @_;
          *$self->{$attribute} = shift;
      };
}

sub internal
#   Used like attribute 'name' => 'val'. The difference being
#   the internal attribute and it accessor are stored as '__name'
{
    my $package = caller;
    my ($attribute, $default) = @_;
    $attribute = "__$attribute";
    no strict 'refs';
    return if defined &{"${package}::$attribute"};
    *{"${package}::$attribute"} =
      sub {
          my $self = shift;
          unless (exists *$self->{$attribute}) {
              *$self->{$attribute} = $default;
          }
          return *$self->{$attribute} unless @_;
          *$self->{$attribute} = shift;
      };
}



1;