package Text::Wigwam::Library::Debug;

    use strict;
    use warnings;
    our $VERSION = '0.01';

    use base q/Exporter/;

    use Text::Wigwam::Const( qw/ STRING ANY BLOCK / );

    our %EXPORT_TAGS = (
        all => [
          qw/
            _proto_try    _try
            _proto_catch  _catch
            _proto_caught _caught
            _proto_throw  _throw
            _proto_error  _error
            _proto_warn   _warn
          /
        ],
        try    => [ qw/ _proto_try    _try / ],
        catch  => [ qw/ _proto_catch  _catch / ],
        caught => [ qw/ _proto_caught _caught / ],
        throw  => [ qw/ _proto_throw  _throw / ],
        error  => [ qw/ _proto_error  _error / ],
        warn   => [ qw/ _proto_warn   _warn / ],
    );
    our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
    our @EXPORT = qw( );

=head1 Name

Text::Wigwam::Library::Debug - A Wigwam directive library.

=head1 Description

This library provides directives which are used for template debugging.

=head1 Usage

The directives within this library can be imported into specific branches of
the directive tree (which transcends from  C<Text::Wigwam::Directives>) via
plug-ins or modules using one of the following techniques.

 package Text::Wigwam::Directives::some::arbitrary::branch;
 # import everything
 use Text::Wigwam::Library::Debug( q/:all/ );

 package Text::Wigwam::Directives::another::arbitrary::branch;
 # import selectively
 use Text::Wigwam::Library::Debug(
  qw/ :try :throw :catch :caught :warn /
 );

=head1 Directives

=cut

sub _proto_try { [ ANY|BLOCK ] }
sub _try {
    my ($Api) = @_;
    $Api->add_global( q/_DIE/ );
    my $data = $Api->get_arg;
    $Api->set_global( Try => \$Api->get_global( q/_DIE/ ) );
    $Api->del_global( q/_DIE/ );
    return $data;
}

=head2 #try I<block>

Traps any exceptions that may occur while executing I<block>. This is useful
for error detection such as when using C<#div> or when executing child
templates. This directive is typically followed by the C<#catch> directive
which can be used to gracefully handle the exception.

 [!! #try #div x y !!]
 [!! #catch { x " divided by " y " caused an error: " #caught } !!]

=cut

sub _proto_catch { [ ANY ] }
sub _catch {
    my ($Api) = @_;
    my $try = $Api->get_global( q/Try/ )
      or die "The #catch directive must follow the #try directive.";
    unless ($$try) {
        $Api->kill_arg(1);
        return;
    };
    $Api->set_global( caught => $$try );
    $Api->set_global( Try => undef );
    my $val = $Api->get_arg;
    $Api->set_global( caught => undef ); # Auto-clear
    return $val;
}

=head2 #catch I<block>

Only executes I<block> if the C<#try> directive has trapped an exception
within the common block scope. Typically I<block> should contain code designed
to handle the exception. The C<#caught> directive can be used to retrieve the
error from within I<block>.

 [!!
  #try #template "foo_primary"
  #catch {
    #try #template "foo_alternate"
    #catch {
      /* Report a custom error message */
      #throw "Problem encountered while loading a required template"
    }
  }
 !!]

=cut

sub _proto_throw { [ STRING ] }
sub _throw { $_[0]->exception( $_[0]->get_arg ); return }

=head2 #throw I<message>

Generates an exception by setting the I<_DIE> Global to I<message>.

 [!! #if no_hope #throw  "I give up" !!]

This exception can be trapped using the C<#try> and C<#catch> directives.

=cut

sub _proto_caught { [ ] }
sub _caught { return $_[0]->get_global(q/caught/) }

=head2 #caught

Returns the error caught by the C<#try> directive from within a C<#caught>
block.

 [!!
  #try #throw "Bite it!"
  #catch { "D'oh! " #caught }
  /* output:  D'oh! Error encountered in root template: Bite it! */
 !!]

Alternatively, you can access the global directly via :caught.

 [!!
  #try #throw "Bite me!"
  #catch { "D'oh! " :caught }
  /* output:  D'oh! Error encountered in root template: Bite me! */
 !!]

=cut

# error is deprecated
sub _proto_error { [ ] }
sub _error { return $_[0]->get_global(q/caught/) }

=head2 #error is DEPRECATED, use #caught instead.

Returns the error caught by the C<#try> directive from within a C<#caught>
block.

 [!!
  #try #throw "An explicitly forced exception"
  #catch { "An error occurred: " #error }
  /* output:  An error occurred: An explicitly forced exception */
 !!]

=cut

sub _proto_warn { [ STRING ] }
#sub _warn { $_[0]->debug( $_[0]->get_arg ); return; }     # Insert a comment
sub _warn {
    my ($Api) =@_;
    my $warn = $Api->get_arg;
    warn $warn;
    $Api->debug( $warn );
    return;
}     # Insert a comment

=head2 #warn I<comment>

Stores I<comment> for display in the template listing when compiled by the
debugger.

=cut

sub init_lib {
    $_[0]->new_global( BLOCK => q/Try/ );
}

1;

