package CGI::Application::Plugin::HTPluginDot;

use strict;
use HTML::Template::Pluggable;
use HTML::Template::Plugin::Dot;
require Exporter;
use vars qw/@ISA @EXPORT_OK $VERSION/;
$VERSION = '1.10';
@ISA = qw(Exporter);
@EXPORT_OK = qw(tmpl_plugindot_load);

sub tmpl_plugindot_load {
	my $self = shift;
	my ($tmpl_file, @extra_params) = @_;

	# add tmpl_path to path array if one is set, otherwise add a path arg
	if (my $tmpl_path = $self->tmpl_path) {
		my @tmpl_paths = (ref $tmpl_path eq 'ARRAY') ? @$tmpl_path : $tmpl_path;
		my $found = 0;
		for( my $x = 0; $x < @extra_params; $x += 2 ) {
			if ($extra_params[$x] eq 'path' and
			ref $extra_params[$x+1] eq 'ARRAY') {
				unshift @{$extra_params[$x+1]}, @tmpl_paths;
				$found = 1;
				last;
			}
		}
		push(@extra_params, path => [ @tmpl_paths ]) unless $found;
	}

    my %tmpl_params;
    my %ht_params = @extra_params;

    $self->call_hook('load_tmpl', \%ht_params, \%tmpl_params, $tmpl_file);

    my $t = HTML::Template::Pluggable->new_file($tmpl_file, %ht_params);

    if (keys %tmpl_params) {
        $t->param(%tmpl_params);
    }

	return $t;
}


sub HTML::Template::_parse {
  my $self = shift;
  my $options = $self->{options};
  
  $options->{debug} and print STDERR "### HTML::Template Debug ### In _parse:\n";
  
  # setup the stacks and maps - they're accessed by typeglobs that
  # reference the top of the stack.  They are masked so that a loop
  # can transparently have its own versions.
  use vars qw(@pstack %pmap @ifstack @ucstack %top_pmap);
  local (*pstack, *ifstack, *pmap, *ucstack, *top_pmap);
  
  # the pstack is the array of scalar refs (plain text from the
  # template file), VARs, LOOPs, IFs and ELSEs that output() works on
  # to produce output.  Looking at output() should make it clear what
  # _parse is trying to accomplish.
  my @pstacks = ([]);
  *pstack = $pstacks[0];
  $self->{parse_stack} = $pstacks[0];
  
  # the pmap binds names to VARs, LOOPs and IFs.  It allows param() to
  # access the right variable.  NOTE: output() does not look at the
  # pmap at all!
  my @pmaps = ({});
  *pmap = $pmaps[0];
  *top_pmap = $pmaps[0];
  $self->{param_map} = $pmaps[0];

  # the ifstack is a temporary stack containing pending ifs and elses
  # waiting for a /if.
  my @ifstacks = ([]);
  *ifstack = $ifstacks[0];

  # the ucstack is a temporary stack containing conditions that need
  # to be bound to param_map entries when their block is finished.
  # This happens when a conditional is encountered before any other
  # reference to its NAME.  Since a conditional can reference VARs and
  # LOOPs it isn't possible to make the link right away.
  my @ucstacks = ([]);
  *ucstack = $ucstacks[0];
  
  # the loopstack is another temp stack for closing loops.  unlike
  # those above it doesn't get scoped inside loops, therefore it
  # doesn't need the typeglob magic.
  my @loopstack = ();

  # the fstack is a stack of filenames and counters that keeps track
  # of which file we're in and where we are in it.  This allows
  # accurate error messages even inside included files!
  # fcounter, fmax and fname are aliases for the current file's info
  use vars qw($fcounter $fname $fmax);
  local (*fcounter, *fname, *fmax);

  my @fstack = ([$options->{filepath} || "/fake/path/for/non/file/template",
                 1, 
                 scalar @{[$self->{template} =~ m/(\n)/g]} + 1
                ]);
  (*fname, *fcounter, *fmax) = \ ( @{$fstack[0]} );

  my $NOOP = HTML::Template::NOOP->new();
  my $ESCAPE = HTML::Template::ESCAPE->new();
  my $JSESCAPE = HTML::Template::JSESCAPE->new();
  my $URLESCAPE = HTML::Template::URLESCAPE->new();

  # all the tags that need NAMEs:
  my %need_names = map { $_ => 1 } 
    qw(TMPL_VAR TMPL_LOOP TMPL_IF TMPL_UNLESS TMPL_INCLUDE);
    
  # variables used below that don't need to be my'd in the loop
  my ($name, $which, $escape, $default);

  # handle the old vanguard format
  $options->{vanguard_compatibility_mode} and 
    $self->{template} =~ s/%([-\w\/\.+]+)%/<TMPL_VAR NAME=$1>/g;

  # now split up template on '<', leaving them in
  my @chunks = split(m/(?=<)/, $self->{template});

  # all done with template
  delete $self->{template};

  # loop through chunks, filling up pstack
  my $last_chunk =  $#chunks;
 CHUNK: for (my $chunk_number = 0;
	    $chunk_number <= $last_chunk;
	    $chunk_number++) {
    next unless defined $chunks[$chunk_number]; 
    my $chunk = $chunks[$chunk_number];
    
    # a general regex to match any and all TMPL_* tags 
    if ($chunk =~ /^<
                    (?:!--\s*)?
                    (
                      \/?[Tt][Mm][Pp][Ll]_
                      (?:
                         (?:[Vv][Aa][Rr])
                         |
                         (?:[Ll][Oo][Oo][Pp])
                         |
                         (?:[Ii][Ff])
                         |
                         (?:[Ee][Ll][Ss][Ee])
                         |
                         (?:[Uu][Nn][Ll][Ee][Ss][Ss])
                         |
                         (?:[Ii][Nn][Cc][Ll][Uu][Dd][Ee])
                      )
                    ) # $1 => $which - start of the tag

                    \s* 

                    # DEFAULT attribute
                    (?:
                      [Dd][Ee][Ff][Aa][Uu][Ll][Tt]
                      \s*=\s*
                      (?:
                        "([^">]*)"  # $2 => double-quoted DEFAULT value "
                        |
                        '([^'>]*)'  # $3 => single-quoted DEFAULT value
                        |
                        ([^\s=>]*)  # $4 => unquoted DEFAULT value
                      )
                    )?

                    \s*

                    # ESCAPE attribute
                    (?:
                      [Ee][Ss][Cc][Aa][Pp][Ee]
                      \s*=\s*
                      (?:
                         (?: 0 | (?:"0") | (?:'0') )
                         |
                         ( 1 | (?:"1") | (?:'1') | 
                           (?:[Hh][Tt][Mm][Ll]) | 
                           (?:"[Hh][Tt][Mm][Ll]") |
                           (?:'[Hh][Tt][Mm][Ll]') |
                           (?:[Uu][Rr][Ll]) | 
                           (?:"[Uu][Rr][Ll]") |
                           (?:'[Uu][Rr][Ll]') |
                           (?:[Jj][Ss]) |
                           (?:"[Jj][Ss]") |
                           (?:'[Jj][Ss]') |
                         )                         # $5 => ESCAPE on
                       )
                    )* # allow multiple ESCAPEs

                    \s*

                    # DEFAULT attribute
                    (?:
                      [Dd][Ee][Ff][Aa][Uu][Ll][Tt]
                      \s*=\s*
                      (?:
                        "([^">]*)"  # $6 => double-quoted DEFAULT value "
                        |
                        '([^'>]*)'  # $7 => single-quoted DEFAULT value
                        |
                        ([^\s=>]*)  # $8 => unquoted DEFAULT value
                      )
                    )?

                    \s*                    

                    # NAME attribute
                    (?:
                      (?:
                        [Nn][Aa][Mm][Ee]
                        \s*=\s*
                      )?
                      (?:
                        "([^">]*)"  # $9 => double-quoted NAME value "
                        |
                        '([^'>]*)'  # $10 => single-quoted NAME value
                        |
                        ([^\s=>]*)  # $11 => unquoted NAME value
                      )
                    )? 
                    
                    \s*

                    # DEFAULT attribute
                    (?:
                      [Dd][Ee][Ff][Aa][Uu][Ll][Tt]
                      \s*=\s*
                      (?:
                        "([^">]*)"  # $12 => double-quoted DEFAULT value "
                        |
                        '([^'>]*)'  # $13 => single-quoted DEFAULT value
                        |
                        ([^\s=>]*)  # $14 => unquoted DEFAULT value
                      )
                    )?

                    \s*

                    # ESCAPE attribute
                    (?:
                      [Ee][Ss][Cc][Aa][Pp][Ee]
                      \s*=\s*
                      (?:
                         (?: 0 | (?:"0") | (?:'0') )
                         |
                         ( 1 | (?:"1") | (?:'1') | 
                           (?:[Hh][Tt][Mm][Ll]) | 
                           (?:"[Hh][Tt][Mm][Ll]") |
                           (?:'[Hh][Tt][Mm][Ll]') |
                           (?:[Uu][Rr][Ll]) | 
                           (?:"[Uu][Rr][Ll]") |
                           (?:'[Uu][Rr][Ll]') |
                           (?:[Jj][Ss]) |
                           (?:"[Jj][Ss]") |
                           (?:'[Jj][Ss]') |
                         )                         # $15 => ESCAPE on
                       )
                    )* # allow multiple ESCAPEs

                    \s*

                    # DEFAULT attribute
                    (?:
                      [Dd][Ee][Ff][Aa][Uu][Ll][Tt]
                      \s*=\s*
                      (?:
                        "([^">]*)"  # $16 => double-quoted DEFAULT value "
                        |
                        '([^'>]*)'  # $17 => single-quoted DEFAULT value
                        |
                        ([^\s=>]*)  # $18 => unquoted DEFAULT value
                      )
                    )?

                    \s*

                    (?:--)?>                    
                    (.*) # $19 => $post - text that comes after the tag
                   $/sx) {

      $which = uc($1); # which tag is it

      $escape = defined $5 ? $5 : defined $15 ? $15 : 0; # escape set?
      
      # what name for the tag?  undef for a /tag at most, one of the
      # following three will be defined
      $name = defined $9 ? $9 : defined $10 ? $10 : defined $11 ? $11 : undef;

      # is there a default?
      $default = defined $2  ? $2  : defined $3  ? $3  : defined $4  ? $4 : 
                 defined $6  ? $6  : defined $7  ? $7  : defined $8  ? $8 : 
                 defined $12 ? $12 : defined $13 ? $13 : defined $14 ? $14 : 
                 defined $16 ? $16 : defined $17 ? $17 : defined $18 ? $18 :
                 undef;

      my $post = $19; # what comes after on the line

      # allow mixed case in filenames, otherwise flatten
      $name = lc($name) unless (not defined $name or $which eq 'TMPL_INCLUDE' or $options->{case_sensitive});

      # die if we need a name and didn't get one
      die "HTML::Template->new() : No NAME given to a $which tag at $fname : line $fcounter." 
        if ($need_names{$which} and (not defined $name or not length $name));

      # die if we got an escape but can't use one
      die "HTML::Template->new() : ESCAPE option invalid in a $which tag at $fname : line $fcounter." if ( $escape and ($which ne 'TMPL_VAR'));

      # die if we got a default but can't use one
      die "HTML::Template->new() : DEFAULT option invalid in a $which tag at $fname : line $fcounter." if ( defined $default and ($which ne 'TMPL_VAR'));
        
      # take actions depending on which tag found
      if ($which eq 'TMPL_VAR') {
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : parsed VAR $name\n";
	
	# if we already have this var, then simply link to the existing
	# HTML::Template::VAR, else create a new one.        
	my $var;        
	if (exists $pmap{$name}) {
	  $var = $pmap{$name};
	  (ref($var) eq 'HTML::Template::VAR') or
	    die "HTML::Template->new() : Already used param name $name as a TMPL_LOOP, found in a TMPL_VAR at $fname : line $fcounter.";
	} else {
	  $var = HTML::Template::VAR->new();
	  $pmap{$name} = $var;
	  $top_pmap{$name} = HTML::Template::VAR->new()
	    if $options->{global_vars} and not exists $top_pmap{$name};
	}

        # if a DEFAULT was provided, push a DEFAULT object on the
        # stack before the variable.
	if (defined $default) {
            push(@pstack, HTML::Template::DEFAULT->new($default));
        }
	
	# if ESCAPE was set, push an ESCAPE op on the stack before
	# the variable.  output will handle the actual work.
	if ($escape) {
          if ($escape =~ /^["']?[Uu][Rr][Ll]["']?$/) {
	    push(@pstack, $URLESCAPE);
	  } elsif ($escape =~ /^"?[Jj][Ss]"?$/) {
	    push(@pstack, $JSESCAPE);
	  } else {
	    push(@pstack, $ESCAPE);
	  }
	}

	push(@pstack, $var);
	
      } elsif ($which eq 'TMPL_LOOP') {
	# we've got a loop start
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : LOOP $name start\n";
	
	# if we already have this loop, then simply link to the existing
	# HTML::Template::LOOP, else create a new one.
	my $loop;
	if (exists $pmap{$name}) {
	  $loop = $pmap{$name};
	  (ref($loop) eq 'HTML::Template::LOOP') or
	    die "HTML::Template->new() : Already used param name $name as a TMPL_VAR, TMPL_IF or TMPL_UNLESS, found in a TMP_LOOP at $fname : line $fcounter!";
	  
	} else {
	  # store the results in a LOOP object - actually just a
	  # thin wrapper around another HTML::Template object.
	  $loop = HTML::Template::LOOP->new();
	  $pmap{$name} = $loop;
	}
	
	# get it on the loopstack, pstack of the enclosing block
	push(@pstack, $loop);
	push(@loopstack, [$loop, $#pstack]);
	
	# magic time - push on a fresh pmap and pstack, adjust the typeglobs.
	# this gives the loop a separate namespace (i.e. pmap and pstack).
	push(@pstacks, []);
	*pstack = $pstacks[$#pstacks];
	push(@pmaps, {});
	*pmap = $pmaps[$#pmaps];
	push(@ifstacks, []);
	*ifstack = $ifstacks[$#ifstacks];
	push(@ucstacks, []);
	*ucstack = $ucstacks[$#ucstacks];
	
	# auto-vivify __FIRST__, __LAST__ and __INNER__ if
	# loop_context_vars is set.  Otherwise, with
	# die_on_bad_params set output() will might cause errors
	# when it tries to set them.
	if ($options->{loop_context_vars}) {
	  $pmap{__first__}   = HTML::Template::VAR->new();
	  $pmap{__inner__}   = HTML::Template::VAR->new();
	  $pmap{__last__}    = HTML::Template::VAR->new();
	  $pmap{__odd__}     = HTML::Template::VAR->new();
	  $pmap{__counter__} = HTML::Template::VAR->new();
	}
	
      } elsif ($which eq '/TMPL_LOOP') {
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : LOOP end\n";
	
	my $loopdata = pop(@loopstack);
	die "HTML::Template->new() : found </TMPL_LOOP> with no matching <TMPL_LOOP> at $fname : line $fcounter!" unless defined $loopdata;
	
	my ($loop, $starts_at) = @$loopdata;
	
	# resolve pending conditionals
	foreach my $uc (@ucstack) {
	  my $var = $uc->[HTML::Template::COND::VARIABLE]; 
	  if (exists($pmap{$var})) {
	    $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var};
	  } else {
	    $pmap{$var} = HTML::Template::VAR->new();
	    $top_pmap{$var} = HTML::Template::VAR->new()
	      if $options->{global_vars} and not exists $top_pmap{$var};
	    $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var};
	  }
	  if (ref($pmap{$var}) eq 'HTML::Template::VAR') {
	    $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR;
	  } else {
	    $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP;
	  }
	}
	
	# get pmap and pstack for the loop, adjust the typeglobs to
	# the enclosing block.
	my $param_map = pop(@pmaps);
	*pmap = $pmaps[$#pmaps];
	my $parse_stack = pop(@pstacks);
	*pstack = $pstacks[$#pstacks];
	
	scalar(@ifstack) and die "HTML::Template->new() : Dangling <TMPL_IF> or <TMPL_UNLESS> in loop ending at $fname : line $fcounter.";
	pop(@ifstacks);
	*ifstack = $ifstacks[$#ifstacks];
	pop(@ucstacks);
	*ucstack = $ucstacks[$#ucstacks];
	
	# instantiate the sub-Template, feeding it parse_stack and
	# param_map.  This means that only the enclosing template
	# does _parse() - sub-templates get their parse_stack and
	# param_map fed to them already filled in.
	my $pkg = ref $self; 
	$loop->[HTML::Template::LOOP::TEMPLATE_HASH]{$starts_at}             
           = $pkg->_new_from_loop(
					   parse_stack => $parse_stack,
					   param_map => $param_map,
					   debug => $options->{debug}, 
					   die_on_bad_params => $options->{die_on_bad_params}, 
					   loop_context_vars => $options->{loop_context_vars},
                                           case_sensitive => $options->{case_sensitive},
					  );
	
      } elsif ($which eq 'TMPL_IF' or $which eq 'TMPL_UNLESS' ) {
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : $which $name start\n";
	
	# if we already have this var, then simply link to the existing
	# HTML::Template::VAR/LOOP, else defer the mapping
	my $var;        
	if (exists $pmap{$name}) {
	  $var = $pmap{$name};
	} else {
	  $var = $name;
	}
	
	# connect the var to a conditional
	my $cond = HTML::Template::COND->new($var);
	if ($which eq 'TMPL_IF') {
	  $cond->[HTML::Template::COND::WHICH] = HTML::Template::COND::WHICH_IF;
	  $cond->[HTML::Template::COND::JUMP_IF_TRUE] = 0;
	} else {
	  $cond->[HTML::Template::COND::WHICH] = HTML::Template::COND::WHICH_UNLESS;
	  $cond->[HTML::Template::COND::JUMP_IF_TRUE] = 1;
	}
	
	# push unconnected conditionals onto the ucstack for
	# resolution later.  Otherwise, save type information now.
	if ($var eq $name) {
	  push(@ucstack, $cond);
	} else {
	  if (ref($var) eq 'HTML::Template::VAR') {
	    $cond->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR;
	  } else {
	    $cond->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP;
	  }
	}
	
	# push what we've got onto the stacks
	push(@pstack, $cond);
	push(@ifstack, $cond);
	
      } elsif ($which eq '/TMPL_IF' or $which eq '/TMPL_UNLESS') {
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : $which end\n";
	
	my $cond = pop(@ifstack);
	die "HTML::Template->new() : found </${which}> with no matching <TMPL_IF> at $fname : line $fcounter." unless defined $cond;
	if ($which eq '/TMPL_IF') {
	  die "HTML::Template->new() : found </TMPL_IF> incorrectly terminating a <TMPL_UNLESS> (use </TMPL_UNLESS>) at $fname : line $fcounter.\n" 
	    if ($cond->[HTML::Template::COND::WHICH] == HTML::Template::COND::WHICH_UNLESS);
	} else {
	  die "HTML::Template->new() : found </TMPL_UNLESS> incorrectly terminating a <TMPL_IF> (use </TMPL_IF>) at $fname : line $fcounter.\n" 
	    if ($cond->[HTML::Template::COND::WHICH] == HTML::Template::COND::WHICH_IF);
	}
	
	# connect the matching to this "address" - place a NOOP to
	# hold the spot.  This allows output() to treat an IF in the
	# assembler-esque "Conditional Jump" mode.
	push(@pstack, $NOOP);
	$cond->[HTML::Template::COND::JUMP_ADDRESS] = $#pstack;
	
      } elsif ($which eq 'TMPL_ELSE') {
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : ELSE\n";
	
	my $cond = pop(@ifstack);
	die "HTML::Template->new() : found <TMPL_ELSE> with no matching <TMPL_IF> or <TMPL_UNLESS> at $fname : line $fcounter." unless defined $cond;
	
	
	my $else = HTML::Template::COND->new($cond->[HTML::Template::COND::VARIABLE]);
	$else->[HTML::Template::COND::WHICH] = $cond->[HTML::Template::COND::WHICH];
	$else->[HTML::Template::COND::JUMP_IF_TRUE] = not $cond->[HTML::Template::COND::JUMP_IF_TRUE];
	
	# need end-block resolution?
	if (defined($cond->[HTML::Template::COND::VARIABLE_TYPE])) {
	  $else->[HTML::Template::COND::VARIABLE_TYPE] = $cond->[HTML::Template::COND::VARIABLE_TYPE];
	} else {
	  push(@ucstack, $else);
	}
	
	push(@pstack, $else);
	push(@ifstack, $else);
	
	# connect the matching to this "address" - thus the if,
	# failing jumps to the ELSE address.  The else then gets
	# elaborated, and of course succeeds.  On the other hand, if
	# the IF fails and falls though, output will reach the else
	# and jump to the /if address.
	$cond->[HTML::Template::COND::JUMP_ADDRESS] = $#pstack;
	
      } elsif ($which eq 'TMPL_INCLUDE') {
	# handle TMPL_INCLUDEs
	$options->{debug} and print STDERR "### HTML::Template Debug ### $fname : line $fcounter : INCLUDE $name \n";
	
	# no includes here, bub
	$options->{no_includes} and croak("HTML::Template : Illegal attempt to use TMPL_INCLUDE in template file : (no_includes => 1)");
	
	my $filename = $name;
	
	# look for the included file...
	my $filepath;
	if ($options->{search_path_on_include}) {
	  $filepath = $self->_find_file($filename);
	} else {
	  $filepath = $self->_find_file($filename, 
					[File::Spec->splitdir($fstack[-1][0])]
				       );
	}
	die "HTML::Template->new() : Cannot open included file $filename : file not found."
	  unless defined($filepath);
	die "HTML::Template->new() : Cannot open included file $filename : $!"
	  unless defined(open(TEMPLATE, $filepath));              
	
	# read into the array
	my $included_template = "";
        while(read(TEMPLATE, $included_template, 10240, length($included_template))) {}
	close(TEMPLATE);
	
	# call filters if necessary
	$self->_call_filters(\$included_template) if @{$options->{filter}};
	
	if ($included_template) { # not empty
	  # handle the old vanguard format - this needs to happen here
	  # since we're not about to do a next CHUNKS.
	  $options->{vanguard_compatibility_mode} and 
	    $included_template =~ s/%([-\w\/\.+]+)%/<TMPL_VAR NAME=$1>/g;
	  
	  # collect mtimes for included files
	  if ($options->{cache} and !$options->{blind_cache}) {
	    $self->{included_mtimes}{$filepath} = (stat($filepath))[9];
	  }
	  
	  # adjust the fstack to point to the included file info
	  push(@fstack, [$filepath, 1,
			 scalar @{[$included_template =~ m/(\n)/g]} + 1]);
	  (*fname, *fcounter, *fmax) = \ ( @{$fstack[$#fstack]} );
	  
          # make sure we aren't infinitely recursing
          die "HTML::Template->new() : likely recursive includes - parsed $options->{max_includes} files deep and giving up (set max_includes higher to allow deeper recursion)." if ($options->{max_includes} and (scalar(@fstack) > $options->{max_includes}));
          
	  # stick the remains of this chunk onto the bottom of the
	  # included text.
	  $included_template .= $post;
	  $post = undef;
	  
	  # move the new chunks into place.  
	  splice(@chunks, $chunk_number, 1,
		 split(m/(?=<)/, $included_template));

	  # recalculate stopping point
	  $last_chunk = $#chunks;

	  # start in on the first line of the included text - nothing
	  # else to do on this line.
	  $chunk = $chunks[$chunk_number];

	  redo CHUNK;
	}
      } else {
	# zuh!?
	die "HTML::Template->new() : Unknown or unmatched TMPL construct at $fname : line $fcounter.";
      }
      # push the rest after the tag
      if (defined($post)) {
	if (ref($pstack[$#pstack]) eq 'SCALAR') {
	  ${$pstack[$#pstack]} .= $post;
	} else {
	  push(@pstack, \$post);
	}
      }
    } else { # just your ordinary markup
      # make sure we didn't reject something TMPL_* but badly formed
      if ($options->{strict}) {
	die "HTML::Template->new() : Syntax error in <TMPL_*> tag at $fname : $fcounter." if ($chunk =~ /<(?:!--\s*)?\/?[Tt][Mm][Pp][Ll]_/);
      }
      
      # push the rest and get next chunk
      if (defined($chunk)) {
	if (ref($pstack[$#pstack]) eq 'SCALAR') {
	  ${$pstack[$#pstack]} .= $chunk;
	} else {
	  push(@pstack, \$chunk);
	}
      }
    }
    # count newlines in chunk and advance line count
    $fcounter += scalar(@{[$chunk =~ m/(\n)/g]});
    # if we just crossed the end of an included file
    # pop off the record and re-alias to the enclosing file's info
    pop(@fstack), (*fname, *fcounter, *fmax) = \ ( @{$fstack[$#fstack]} )
      if ($fcounter > $fmax);
    
  } # next CHUNK

  # make sure we don't have dangling IF or LOOP blocks
  scalar(@ifstack) and die "HTML::Template->new() : At least one <TMPL_IF> or <TMPL_UNLESS> not terminated at end of file!";
  scalar(@loopstack) and die "HTML::Template->new() : At least one <TMPL_LOOP> not terminated at end of file!";

  # resolve pending conditionals
  foreach my $uc (@ucstack) {
    my $var = $uc->[HTML::Template::COND::VARIABLE]; 
    if (exists($pmap{$var})) {
      $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var};
    } else {
      $pmap{$var} = HTML::Template::VAR->new();
      $top_pmap{$var} = HTML::Template::VAR->new()
        if $options->{global_vars} and not exists $top_pmap{$var};
      $uc->[HTML::Template::COND::VARIABLE] = $pmap{$var};
    }
    if (ref($pmap{$var}) eq 'HTML::Template::VAR') {
      $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_VAR;
    } else {
      $uc->[HTML::Template::COND::VARIABLE_TYPE] = HTML::Template::COND::VARIABLE_TYPE_LOOP;
    }
  }

  # want a stack dump?
  if ($options->{stack_debug}) {
    require 'Data/Dumper.pm';
    print STDERR "### HTML::Template _param Stack Dump ###\n\n", Data::Dumper::Dumper($self->{parse_stack}), "\n";
  }

  # get rid of filters - they cause runtime errors if Storable tries
  # to store them.  This can happen under global_vars.
  delete $options->{filter};
}



1;


