package DTL::Fast::Template;
use strict; use utf8; use warnings FATAL => 'all'; 
use parent 'DTL::Fast::Parser';

use DTL::Fast qw(get_template);
use DTL::Fast::Context;
use DTL::Fast::Tags;
use DTL::Fast::Filters;    

our $CURRENT_TEMPLATE;  # global variable for linking  modules

#@Override
sub new
{
    my( $proto, $template, %kwargs ) = @_;
    $template //= '';

    $kwargs{'raw_chunks'} = _get_raw_chunks($template);
    $kwargs{'dirs'} //= [];             # optional dirs to look up for includes or parents
    $kwargs{'file_path'} //= 'inline';  
    $kwargs{'perl'} = $];
    $kwargs{'blocks'} = {};
    $kwargs{'modules'} //= {
        'DTL::Fast' => $DTL::Fast::VERSION,
    };

    
    my $self = $proto->SUPER::new(%kwargs);
    
    return $self;
}


#@Override
sub parse_chunks
{
    my( $self ) = @_;
    
    my $current_template_backup = $CURRENT_TEMPLATE;
    $CURRENT_TEMPLATE = $self;
    
    $self->SUPER::parse_chunks();
    
    $CURRENT_TEMPLATE = $current_template_backup;
    return $self;
}

my $reg = qr/(
     \{\#.+?\#\}
    |\{\%.+?\%\}
    |\{\{.+?\}\}
)/xs;

sub _get_raw_chunks
{
    my( $template ) = @_;

    my $result = [split $reg, $template];
    
    return $result;    
}

#@Override
sub render
{
    my( $self, $context ) = @_;

    $context //= {};
    
    if( ref $context eq 'HASH' )
    {
        $context = DTL::Fast::Context->new($context);
    }
    elsif( 
        defined $context 
        and ref $context ne 'DTL::Fast::Context'
    )
    {
        die  "Context must be a DTL::Fast::Context object or a HASH reference";
    }
    
    $context->push_scope();
    
    $context->{'ns'}->[-1]->{'_dtl_ssi_dirs'} = $self->{'ssi_dirs'} if $self->{'ssi_dirs'};
    $context->{'ns'}->[-1]->{'_dtl_url_source'} = $self->{'url_source'} if $self->{'url_source'};

    my $template_path = $self->{'file_path'};

    if( not exists $context->{'ns'}->[-1]->{'_dtl_include_path'} )  # entry point
    {
        $context->{'ns'}->[-1]->{'_dtl_include_path'} = [];
        $context->{'ns'}->[-1]->{'_dtl_include_files'} = {};
    }
    else    # check for recursion, shouldn't this be in the include tag?
    {
        if( exists $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path} )
        {
            # recursive inclusion
            die sprintf("Recursive inclusion detected:\n%s\n"
                , join( "\n includes ", @{$context->{'ns'}->[-1]->{'_dtl_include_path'}}, $template_path)
            );
        }
    }
    
    $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path} = 1;
    push @{$context->{'ns'}->[-1]->{'_dtl_include_path'}}, $template_path;
  
    my $result;
    if ( $self->{'extends'} ) # has parent template
    {
        my @descendants = ();
        my $current_descendant = $self; 
        my %inheritance = ();
        
        while( $current_descendant->{'extends'} )
        {
            push @descendants, $current_descendant;
            $inheritance{$current_descendant->{'file_path'}} = 1;
            
            my $parent_template_name = $current_descendant->{'extends'}->render($context);
                        
            die sprintf(
                "Unable to resolve parent template name for %s"
                , $current_descendant->{'file_path'}
            ) if not $parent_template_name;
            
            $current_descendant = get_template(
                $parent_template_name 
                , 'dirs' => $self->{'dirs'}
            );
            
            if ( defined $current_descendant )
            {
                if ( $inheritance{$current_descendant->{'file_path'}} )
                {
                    die  sprintf(
                        "Recursive inheritance detected:\n%s\n" 
                        , join(
                            "\n inherited from ",
                            (map {$_->{'file_path'}} @descendants),
                            $current_descendant->{'file_path'}
                        )
                    );
                }
            }
            else
            {
                die  sprintf( "Couldn't found a parent template: %s in one of the following directories: %s"
                    , $parent_template_name 
                    , join( ', ', @{$self->{'dirs'}})
                );
            }
        }
        
        push @descendants, $current_descendant;
        $context->{'ns'}->[-1]->{'_dtl_descendants'} = \@descendants;
        $context->{'ns'}->[-1]->{'_dtl_rendering_template'} = $current_descendant;
        $result = $current_descendant->SUPER::render($context);

    }
    else
    {
        delete $context->{'ns'}->[-1]->{'_dtl_descendants'};
        $context->{'ns'}->[-1]->{'_dtl_rendering_template'} = $self;
        $result = $self->SUPER::render($context);
    }
    
    pop @{$context->{'ns'}->[-1]->{'_dtl_include_path'}};
    delete $context->{'ns'}->[-1]->{'_dtl_include_files'}->{$template_path};
    
    $context->pop_scope();
    
    return $result;
}

1;