
package Text::Wigwam::Engine::Totem::Argument;

    use strict;
    use warnings;
    no warnings q/recursion/;
    use integer;
    our $VERSION = '0.01';

    use base 'Text::Wigwam::Cast';
    use Text::Wigwam::Const( q/:all/ );

sub new {
    my ($class, $drip) = @_;
    return bless {
        ARGS => $drip->args,
        DRIP => $drip,
        CURR => 0,
    };
}

sub exec_arg {
    my ($Arg, $Api) = @_;
    my ($args, $curr) = @$Arg{qw/ARGS CURR/};
    if ($curr == scalar @$args) {
        $Api->exception(
            "Arguments exhausted in directive "
          . $Arg->{DRIP}->token
          . " (pulling too many?)"
        );
        return $Arg->null_data($args->[-1])
          if scalar @$args;
        return;
    }
    my $want = $args->[$curr];
    my $core = $Api->{core};

    if( 
        $Api->eflag
#     || (
#         && $core->curr_token->can(q/once/)
#         && $core->curr_token->once
#        )
    ){
        $Arg->skip($Api);
        return ($want & TERM) ? [] : $Arg->null_data($want);
    }

    return $Arg->_exec_list($Api, $core, $want)
      if $want & TERM;

    return $Arg->_expr( $Api, $core, $want )
      if $want & EXPR;

    if ($want & ITERATE) {
        $core->temp_addr( $core->curr_addr );
        my $value = $core->curr_token->exec( $want, $Arg, $Api, $core );
        $core->temp_addr;
        return $value;
    }
    my $value = $core->curr_token->exec( $want, $Arg, $Api, $core );
    $Arg->next;
    return $value;
}

sub _exec_list {
    my ($Arg, $Api, $core, $want) = @_;
    my @results;
    my $endl = \$Arg->{ENDL};
    until(0){
        if( $Api->eflag ){
            $Arg->skip($Api);
            last;
        }
        my $value = $core->curr_token->exec( $want, $Arg, $Api, $core );
        if( $$endl ){
            $$endl = 0;
            $Arg->next;
            last;
        }
        push( @results, $value );
    }
    return \@results;
}

=begin caching exec_list
# This version of exec_list attempts to cache static lists, but until the
# argument class can itself be cached, it'll probably remain slower than
# non-caching version.

sub _exec_list {
    my ($Arg, $Api, $core, $want) = @_;
    my $status = \($Arg->{LCACH} ||= [])->[$Arg->{CURR}];
#    return $Arg->skip($Api) if $Arg->curr_token->once;
#    if (ref $$status || $Arg->curr_token->once){
    if (ref $$status){
        $Arg->skip($Api);
        return $$status;
    }
    my @results;
    my $endl = \$Arg->{ENDL};
    until(0){
        my $value
          = (my $token=$core->curr_token)->exec($want, $Arg, $Api, $core);
        if( $Api->eflag ){
            $Arg->skip($Api);
            return \@results;
        }
        last if $$endl;
        $$status ||= !$Arg->is_static($token);
        push( @results, $value );
    }
    $$endl = 0;
    $Arg->next;

    return \@results if $$status;
    return $$status = \@results;
}
sub is_static {
    my ($Arg, $token) = @_;
    return (
        $token->isa(q/Text::Wigwam::Engine::Totem::Token::Literal/)
     || (
            ($Arg->want & VAR)
         && $token->isa(q/Text::Wigwam::Engine::Totem::Token::Variable/)
        )
    ) ? 1 : 0;
}

=end caching exec_list
=cut

sub skip {
     # This method is the equivalent of kill_arg(1)
    my ($Arg, $Api) = @_;
    my ($args, $drip, $curr, $index) = @$Arg{qw/ARGS DRIP CURR INDEX/};
    my $core = $Api->{core};

    if( ($index ||= $Arg->{INDEX} = [])->[$curr] ){
        $Arg->next;
        return $Api->{core}->curr_addr($index->[$curr]);
    }

    my $term = $args->[$curr] & TERM;

    1 until(
        $core->curr_token->skip(
            $term,
            $Arg,
            $Api,
            $core,
        ) || !$term
    );
    $Arg->next;
    $index->[$curr] = $Api->{core}->curr_addr;
    return;
}

sub list {
 # This method creates a data structure useful for rendering the
 # argument for display
    my ($Arg, $Api) = @_;
    my ($args, $drip, $curr) = @$Arg{qw/ARGS DRIP CURR/};
    my $core = $Api->{core};
    my ($val, $end);
    if( $Arg->want & TERM ){
       my $list=Text::Wigwam::Engine::Totem::Paint::Sublist->new;
       until( $end ){
          ( $val, $end ) = $core->curr_token->paint(
              $Arg,
              $Api,
              $core,
          );
          $list->add(
              Text::Wigwam::Engine::Totem::Paint::Group->new($val)
          );
       }
       $Arg->next;
       return $list;
    }
    else {
        ($val) = $core->curr_token->paint(
            $Arg,
            $Api,
            $core,
        );
    }
    $Arg->next;
    return Text::Wigwam::Engine::Totem::Paint::Group->new($val);
}

sub want     { $_[0]->{ARGS}[$_[0]->{CURR}] }
sub drip     { $_[0]->{DRIP} }
sub init     { $_[0]->{CURR} = $_[0]->{ENDL} = 0; return $_[0] }
sub clone    { return bless { %{$_[0]}, CURR => 0 }, ref($_[0]) }
sub end_list { $_[0]->{ENDL} = $_[1] }
sub next     {
    my ($Arg) = @_;
    ++$Arg->{CURR} if $Arg->{CURR} < scalar @{$Arg->{ARGS}};
}
sub remain   { scalar @{$_[0]->{ARGS}} - $_[0]->{CURR} }
sub args     { $_[0]->{ARGS} }
sub type     { $_[0]->{TYPE} ||= $_[0]->{DRIP}->type }
sub mate {
    my ($Arg) = @_;
    return $Arg->{MATE} ||= $Arg->drip->mate;
}

 # null_data is used in situations where an exception has
 # occurred, and we just want to satisfy the calling directive's
 # needs so that we can make a clean exit.

sub null_data {
     # returns a null value of the calling directive's expected data type
    my ($Arg, $want) = @_;

    return
        $want & ARRAY          ? [] 
      : $want & HASH           ? {}
      : $want & SCALAR         ? \do { my $v = '' }
      : $want & (BLESSED|EXPR) ? Text::Wigwam::Nulldata->new
      : $want & CODE           ? sub {}
      : $want & (NUM|BOOLEAN)  ? 0
      : ""
    ;
}

sub _expr {
    my ($Arg, $Api, $core, $want) = @_;
    my $addr = $core->curr_addr();
    $Arg->skip($Api);
    return Text::Wigwam::Engine::Totem::Expression->new(
        $addr,
        $want,
        $core->curr_addr - $addr,
        $Api,
    );
}

1;
