package Text::Wigwam::Engine;

# This is the base class which must be inherited by all Wigwam engines.
# This class combined with any given Engine's basic methods makes up a
# full fledged API.

    use strict;
    no strict "refs"; 
    use warnings;
    no warnings 'uninitialized';
    our $VERSION = '0.01';

    use base qw/Text::Wigwam::Api Text::Wigwam::Cast::Base/;

#    use Scalar::Util( qw/ blessed reftype / );
    use File::Spec::Functions( qw/catfile/ );
    use Text::Wigwam::Template;

     # Catch invalid method calls
    sub AUTOLOAD {
        return if our $AUTOLOAD =~ /::DESTROY$/;
        my( $meth ) = $AUTOLOAD =~ /.*::(.*)$/;
        my( undef, $file, $line ) = caller();
        $_[0]->exception(
            "Attempted call to a non-existent API method '$meth' in $file, line $line."
        );
        return;
    }

     # API/Engine constructor
    sub new {
        my ($class, %Opts) = @_;

        my %opts = ();
        map { $opts{ lc $_ } = $Opts{$_} } keys %Opts;

        my $Api = bless {}, ref($class) || $class;
        @$Api{
          qw/
            d_tree
            document
            globals
            stash
            mod_time
            config
            paths
            export
            comments
          /
        } = (
            @opts{
              qw/
                dtree
                doc
                globals
                stash
                modtime
                config
                paths
                export
              /
            },
            {}
        );
        return $Api;
    }
    sub dtree    { $_[0]->{d_tree}   }
    sub globals  { $_[0]->{globals}  }
    sub stash    { $_[0]->{stash}    }
    sub config   { $_[0]->{config}   }
    sub paths    { $_[0]->{paths}    }
    sub doc      { $_[0]->{document} }
    sub exports  { $_[0]->{export}   }
    sub comments { $_[0]->{comments} }
    sub add_comment {
        my ($Api, $err, $addr) = @_;
        $Api->comments->{$addr||$Api->curr_addr} = $err;
    }
    sub get_comments { return { %{$_[0]->comments} } }

     # Global API/Engine methods follow.
     # Be careful about overriding any of these methods.

    sub name { return $_[0]->get_options( qw/engine/ ) }

    sub load_modules {
        my ($self, @mlist) = @_;
     # Modules need to be loaded into the appropriate namespace.
     # This is handled by Text::Wigwam::Directives, itself.
        return Text::Wigwam::Directives->load_up(
            {},
            {},
            Text::Wigwam::ApiJr->new( $self->globals ),
            $self->paths->finder( q/modules/ ),
#            split( /\s*,\s*/, $_[1] ),
            @mlist,
        );
    }

    sub load_perlmod {
        my ($self, @pmods) = @_;
        $_ =~ s{::}{/}g for @pmods;
        my @pmlist;
        for my $pmod (@pmods) {
            push (@pmlist, $pmod) unless exists $INC{"$pmod.pm"};
        }
#        return unless @pmlist;
        local $@;
        eval {
         Text::Wigwam::Loader->fetch_package(
            {},
            Text::Wigwam::ApiJr->new( $self->globals ),
            $self->paths->finder( q/perlmod/ ),
            @pmlist,
         );
        };
        return $@;
    }

     # Template debugging and error handling routines
    sub exception {
        my ($Api, $error, $addr) = @_;
        $error =~ s/\n//gs;
        my $msg = 'Error encountered in '. $Api->docname .": $error";
#warn $msg;
        $Api->debug( $error, $addr );
        $Api->globals->set_global( _DIE => \$msg );
        return $msg;
    }

    sub debug {
        my ($Api, $err, $addr) = @_;
        $Api->_bug( $err, $addr );
        return;
    }

# Private stuff

    sub _bug {
        my ($Api, $err, $addr) = @_;
        $addr = length($addr) ? $addr : $Api->curr_addr;
        my $expr = $Api->root_expr;
         # There should already be a BUGS object here at this
         # point, but just to be safe..
        my $bugs = $Api->globals->get_global(q/_BUGS/) ||
            $Api->globals->set_global(
                _BUGS => Text::Wigwam::Debug->new(),
            )
        ;
        $bugs->add(
            Text::Wigwam::Debug::Bug->new(
                $expr,
                $err,
                $addr,
                $Api,
                {$Api->get_options},
            )
        );
    }

1;
