
package Text::Wigwam::Engine::Fusion::Token::Directive;

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

    use base q/Text::Wigwam::Cast/;

    use Text::Wigwam::Const(
       qw/
        BLOCK
        ARRAY
        HASH
        TERM
        STRING
        VAR
        ANY
        VOID
        RUNONCE
      /
    );

    use Text::Wigwam::Engine::Fusion::Const(
      qw/
        TEXT_BLOCK
        CODE_BLOCK
        FAKED
      /
    );

    sub new {
        my ($class, @params) = @_;
        my %self;
        @self{qw/
            DATA
            DRAW
            MATE
            TYPE
            ONCE
        /} = @params;
        return bless \%self, ref($class) || $class;
    }
    sub mate {
        my ($tokn) = @_;
        return $tokn->{MATE} if ($tokn->type);
        return $tokn->{MATE} ||=
          join(
            "" =>
            "#/",
            substr($_[0]->{DATA}, 1)
        );
    }
    sub drip {
            # Don't cache here.
        return
            $_[0]->{DRIP}
         || Text::Wigwam::Engine::Fusion::Drip->new(@_);
    }
    sub dcache { $_[0]->{DRIP} = $_[1] }
    sub next { $_[0]->{NEXT} ||= $_[1] }
    sub once { $_[0]->{ONCE}++ > 1 }
    sub data { $_[0]->{DATA} }
    sub type { $_[0]->{TYPE} || 0 }
    sub exec {
        my ($tokn, $want, $pArg, $Api, $core) = @_;
        $core->next_token;

         # Processing a directive
        my $drip = $tokn->drip($Api);
        my (undef, undef, $token, $handler, $vars) = @$drip; # $drip->expand; # CHEATER!
        my $Arg = $Api->_new_arg(
            Text::Wigwam::Engine::Fusion::Argument->new($drip)
        );

        if ($want & RUNONCE) {
            $tokn->{ONCE} ||= 1;
            if( $tokn->once ) {
                $Api->kill_arg($Arg->remain);
                $Api->_pop_arg;
                return $Arg->null_data($want);
            }
        }
        elsif ($tokn->{ONCE} && $tokn->once) {
            $Api->exception( 'Priority directive called in non-VOID context' )
               unless ($want & VOID);
            $Api->kill_arg($Arg->remain);
            $Api->_pop_arg;
            return $Arg->null_data($want);
        }

        $Api->inc_scope( q/BLOCK/ ) if BLOCK & $want;
        $Api->add_global( @$vars ) if $vars;
        local $@;
        my $value = eval {
            $handler->(
                $Api,
                ($want & (HASH|ARRAY|ANY)) ? 1 : 0,  # List context
                ($want & VOID),
            )
        };
        my $err = $@;

        $Api->del_global( @$vars ) if $vars;
        $Api->dec_scope( q/BLOCK/ ) if BLOCK & $want;

        $Api->_pop_arg;

        if( (my $remain = $Arg->remain) || $err ) {
            $err ||= "$token did not pull all of its arguments, $remain remain.";
            $Api->exception( $err );
            $Api->kill_arg($remain) if $remain;
            return $Arg->null_data($want);
        }
        $tokn->{NEXT} ||= $Api->curr_addr;
        return $tokn->cast(
            $pArg,
            $Api,
            $want,
            $tokn->wg_type( $Api, $value ),
            $value
        );
    }
    sub skip {
        my ($tokn, $list, $pArg, $Api, $core) = @_;
        $core->curr_addr($tokn->{NEXT}), return undef if $tokn->{NEXT};
        $core->next_token;
        return $core->curr_token->skip( $list, $pArg, $Api, $core )
          if( $pArg->type & TEXT_BLOCK) && !($tokn->type & TEXT_BLOCK);

        my $Arg = $Api->_new_arg(
            Text::Wigwam::Engine::Fusion::Argument->new(
                $tokn->drip($Api),
            )
        );

        $Arg->skip($Api) while( $Arg->remain );
        $Api->_pop_arg;
        $tokn->{NEXT} = $core->curr_addr;
        return;
    }

    sub paint {
        my ($tokn, $pArg, $Api, $core) = @_;
        my $drip = $tokn->drip($Api, 1);
        my $Arg = $Api->_new_arg(
            Text::Wigwam::Engine::Fusion::Argument->new($drip)
        );

        $core->next_token;
        my $itemlist = Text::Wigwam::Engine::Fusion::Paint::Group->new(
            $tokn->_paint(
                $Api,
                ($Arg->type & FAKED) ?
                    $drip->error || "Unreported error"
                 :
                    '',
                $core
            )
        );

        while( $Arg->remain ){
          no warnings 'uninitialized';
          if( $Arg->want & TERM ){
            my ($text, $end);
            my $list = Text::Wigwam::Engine::Fusion::Paint::Sublist->new(
                Text::Wigwam::Engine::Fusion::Paint::Group->new
            );
            while( !$end ){
                ($text, $end)=$core->curr_token->paint(
                    $Arg,
                    $Api,
                    $core
                );
                $list->add( $text ) unless $end;
            }
            $itemlist->add( $list, $text );
          }
          else{
            my ($text) = $core->curr_token->paint(
                $Arg,
                $Api,
                $core
            );
            $itemlist->add( @$text );
          }
          $Arg->next;
        }
        $tokn->{NEXT} = $core->curr_addr;
        $Api->_pop_arg;
        return( $itemlist, undef );
    }

    sub _paint {
        my ($self, $Api, $error, $core) = @_;
        if( 0 && scalar @{$self->{DRAW}} == 2 ){
            return Text::Wigwam::Engine::Fusion::Paint::Group->new(
             [
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[0],
                $core->curr_addr,
                'directive'
              ),
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[1],
                $core->curr_addr,
                'tagentity'
              ),
             ]
            ) unless $error;

            $Api->add_comment( $error );
            return Text::Wigwam::Engine::Fusion::Paint::Group->new(
             [
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[0],
                $core->curr_addr,
                'error',
              ),
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[1],
                $core->curr_addr,
                'tagentity',
              ),
             ]
            );
        }
        unless ( $self->type & (TEXT_BLOCK | CODE_BLOCK) ) {
            return Text::Wigwam::Engine::Fusion::Paint::Group->new(
             [
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[0],
                $core->curr_addr,
                'directive',
              ),
             ],
            ) unless $error;
            $Api->add_comment( $error );
            return Text::Wigwam::Engine::Fusion::Paint::Group->new(
             [
              Text::Wigwam::Engine::Fusion::Paint::Token->new(
                $self->{DRAW}[0],
                $core->curr_addr,
                'error',
              ),
             ],
            );
        }
        return Text::Wigwam::Engine::Fusion::Paint::Group->new(
         [
          Text::Wigwam::Engine::Fusion::Paint::Token->new(
            $self->{DRAW}[0],
            $core->curr_addr,
            'tagentity'
          )
         ]
        ) unless $error;
        $Api->add_comment( $error );
        return Text::Wigwam::Engine::Fusion::Paint::Group->new(
         [
          Text::Wigwam::Engine::Fusion::Paint::Token->new(
            $self->{DRAW}[0],
            $core->curr_addr,
            'error'
          )
         ]
        );
    }

1;
