use v5.20;
use feature qw(signatures);
no warnings qw(experimental::signatures);


package Pod::PseudoPod::PerlTricks::HTML;
use strict;
use parent 'Pod::PseudoPod::PerlTricks';

use warnings;
no warnings;

use subs qw();
use vars qw($VERSION);

use Carp;
use Data::Dumper;

$VERSION = '0.011';

sub DEBUG () { 0 }

=encoding utf8

=head1 NAME

Pod::PseudoPod::PerlTricks - Turn Pod into the HTML PerlTricks needs

=head1 SYNOPSIS

	use Pod::PseudoPod::PerlTricks;

=head1 DESCRIPTION

***THIS IS ALPHA SOFTWARE. MAJOR PARTS WILL CHANGE***

I wrote just enough of this module to get my job done, and I skipped
every part of the specification I didn't need while still making it
flexible enough to handle stuff later.


PerlTricks.com Style Guide v0.01
========================== =====
By David Farrell

Introduction
------------
This document is intended to guide PerlTricks authors in producing articles that are consistent with the aims of the website. None of this is set in stone - great writing should always prevail.

Goal
----
We aspire to reasoned, insightful, professional writing with a lighthearted bent.

Topics of interest
------------------
- Anything Perl related: news, events, tutorials, community
- Non-Perl programming subjects: version control, hosting, sysadmin
- Open Source

Looking for an idea for an article? Our bread and butter is: "here is something cool you can do with Perl". Start there.

Politics / Tone
---------------
- We are pro: Perl, Open Source and free software
- No rants or "hit pieces"
- Reasoned criticism is fine

Language
--------
- American English
- 300-1,000 words per article
- Simple English (use http://www.hemingwayapp.com/ to help)
- Only capitalize the first letter of a word in headings (no title case)
- Articles can begin with an italicised introductory paragraph
- Technical terms / references when first used should be quoted in speech marks (")
- Use the first-person
- We are "PerlTricks.com"
- You can use "we" to refer to PerlTricks.com, the staff, our point of view etc.
- When referring to modules for the first time, provide a link to metacpan

Markup
------
- HTML
- <h3> for sub-headers
- <p> for paragraphs
- <a> for links
- <code> for inline code
- <pre class="prettyprint lang-perl"><code></code></pre> for Perl code block
- <pre><code><span class="nocode"></span></code></pre> for plain code block
- <blockquote><div class="quote"></div></blockquote> for blockquote
- <i>, <b> can be used for emphasis
- <ul>, <table> are supported
- Inline images ... can be done, let me know if you need them and I'll upload in the backend

Questions or comments ? Email me: perltricks.com@gmail.com



=cut

=over 4

=cut

sub _ponder_begin ( $self, $para, $curr_open, $paras ){
	# XXX this is such a messed up way to do this, but this is
	# not designed to be extended
	unless ($para->[2] =~ /^\s*(?:output|terminal|code)/) {
		return $self->SUPER::_ponder_begin($para,$curr_open,$paras);
		}

	my $content = join ' ', splice @$para, 2;
	$content =~ s/^\s+//s;
	$content =~ s/\s+$//s;

	my ($target, $title) = $content =~ m/^(\S+)\s*(.*)$/;
	$para->[1]{'target'} = $target;  # without any ':'

	return 1 unless $self->{'accept_targets'}{$target};

	$para->[0] = '=for';  # Just what we happen to call these, internally
	$para->[1]{'~really'} ||= '=begin';
	$para->[1]{'~resolve'} = 1;

	push @$curr_open, $para;
	$self->{'content_seen'} ||= 1;

	$self->_handle_element_start( $target, $para->[1] );

	return 1;
	}

sub begin_for ( $self, $attributes={} ) {
	my $target = $attributes->{target};
	my $method =  'start_' . $target;

	if( $self->can( $method ) ) {
		$self->$method();
		}
	else {
		DEBUG > 1 and print "No method $method";
		}
	}

sub end_for ( $self, $attributes={} ) {
	my $target = $attributes->{target};
	my $method =  'end_' . $target;

	if( $self->can( $method ) ) {
		$self->$method();
		}
	else {
		DEBUG > 1 and print "No method $method";
		}
	}

sub add_html_tag ( $self, $stuff ) {
	$self->add_to_pad( $stuff );
	$self->emit;
	}

sub add_data ( $self, $stuff ) {
	$self->add_to_pad( $stuff );
	$self->escape_and_emit;
	}

sub escape_and_emit ( $self ) {
	my $pad = $self->get_pad;

	$self->{$pad} =~ s/\s+\z//;

	$self->{$pad} =~ s/&/&amp;/g;
	$self->{$pad} =~ s/</&lt;/g;
	$self->{$pad} =~ s/>/&gt;/g;

	$self->emit;
	}

sub add_to_pad ( $self, $stuff ) {
	my $pad = $self->get_pad;
	$self->{$pad} .= $stuff;
	}

sub clear_pad ( $self ) {
	my $pad = $self->get_pad;
	$self->{$pad} = '';
	}

sub set_title ( $self, $title ) { $self->{title} = $title }

sub title ( $self ) { $self->{title} }

=item document_header

The empty string. We don't worry about that here. The blogging
platform adds that.

=cut

sub document_header ( $self ) { '' }

=item document_footer

The empty string. We don't worry about that here. The blogging
platform adds that.

=cut

sub document_footer ( $self ) { '' }

=back

=head2 The Pod::Simple mechanics

Everything else is the same stuff from C<Pod::Simple>.

=over 4

=cut

sub emit ( $self, $attributes={} ) {
	print {$self->{'output_fh'}} $self->get_from_current_pad;
	$self->clear_pad;
	return;
	}

sub get_pad ( $self, $attributes={} ) {
	# flow elements first
	   if( $self->{module_flag}   ) { 'scratch'     }
	elsif( $self->{in_U}      )     { 'url_text'    }
	elsif( $self->{in_L}      )     { 'link_text'   }
	elsif( $self->{in_output} )     { 'output_text' }
	elsif( $self->{in_code} )       { 'code_text'     }
	elsif( $self->{in_terminal} )   { 'terminal_text' }
	elsif( $self->{in_figure} )     { 'figure_text'   }
	# then block elements
	# finally the default
	else                            { 'scratch'     }
	}

sub get_from_current_pad ( $self ) {
	my $pad = $self->get_pad;
	$self->{$pad};
	}

sub add_to_current_pad ( $self, $text ) {
	my $pad = $self->get_pad;
	$self->{$pad} .= $text;
	}

sub start_Document ( $self, $attributes={} ) {
	$self->{in_section} = [];
	$self->add_to_pad( $self->document_header );
	$self->emit;
	}

sub end_Document ( $self, $attributes={} ) {
	$self->add_to_pad( $self->document_footer );
	$self->emit;
	}

sub _header_start ( $self, $level=1 ) {
	$self->{in_header} = 1;
	$self->add_html_tag( qq|<h$level>| );
	}
sub _header_end   ( $self, $level=1 ) {
	$self->{in_header} = 0;
	$self->add_html_tag( "</h$level>\n\n" );
	}

sub start_head0  ( $self, $attributes={} ) { $self->_header_start( 0 ); }
sub end_head0    ( $self, $attributes={} ) { $self->_header_end( 0 );   }

sub end_head1    ( $self, $attributes={} ) { $self->_header_end( 1 );   }
sub start_head1  ( $self, $attributes={} ) { $self->_header_start( 1 ); }

sub end_head2    ( $self, $attributes={} ) { $self->_header_end( 2 );   }
sub start_head2  ( $self, $attributes={} ) { $self->_header_start( 2 ); }

sub start_head3  ( $self, $attributes={} ) { $self->_header_start( 3 ); }
sub end_head3    ( $self, $attributes={} ) { $self->_header_end( 3 );   }


sub end_non_code_text ( $self, $attributes={} ) {
	$self->make_curly_quotes;

	$self->emit;
	}

sub make_para ( $self, $style, $para ) {
	$self->add_html_tag( '<p>' );
	$self->add_to_pad( $para );
	$self->escape_and_emit;
	$self->add_html_tag( "<\p>\n\n" );
	}

sub start_Para ( $self, $attributes={} ) {
	return if $self->{in_figure};
	$self->add_html_tag( qq|<p>| );

	$self->escape_and_emit;

	$self->{'in_para'} = 1;
	}
sub end_Para   ( $self, $attributes={} ) {
	return if $self->{in_figure};
	$self->add_html_tag( "</p>\n\n" );

	$self->end_non_code_text;

	$self->{'in_para'} = 0;
	}

=item * start_Verbatim

=item * end_Verbatim

This is for the code and output sections.

=cut

sub start_Verbatim ( $self, $attributes={} ) {
	$self->{'in_verbatim'} = 1;
	my $sequence = ++$self->{'verbatim_sequence'};

	if( $self->{'in_output'} ) {
		$self->add_html_tag( qq|\n\n<pre class="output">| );
		}
	elsif( $self->{'in_code'} ) {
		$self->add_html_tag( qq|\n\n<pre class="prettyprint lang-perl"><code>| );
		}
	elsif( $self->{'in_terminal'} ) {
		$self->add_html_tag( qq|\n\n<pre class="terminal"><code>| );
		}
	else {
		$self->add_html_tag( qq|\n\n<pre class="general">| );
		}

	$self->emit;
	}

sub end_Verbatim ( $self, $attributes={} ) {
	if( $self->{'in_output'} ) {
		$self->add_html_tag( qq|</pre>\n\n| );
		}
	elsif( $self->{'in_code'} ) {
		$self->add_html_tag( qq|</code></pre>\n\n| );
		}
	elsif( $self->{'in_terminal'} ) {
		$self->add_html_tag( qq|</code></pre>\n\n| );
		}
	else {
		$self->add_html_tag( qq|</pre>\n\n| );
		}

	$self->{'in_verbatim'} = 0;
	}

=item * start_output

=item * end_output

These methods simple set flags and defer everything else to the
verbatim handler.

=cut

sub start_output   ( $self, $attributes={} ) {
	$self->{'in_output'} = 1;
	}
sub end_output     ( $self, $attributes={} ) {
	$self->{'in_output'} = 0;
	}

sub start_code     ( $self, $attributes={} ) {
	$self->{'in_code'} = 1;
	}
sub end_code       ( $self, $attributes={} ) {
	$self->{'in_code'} = 0;
	}

sub start_terminal ( $self, $attributes={} ) {
	$self->{'in_terminal'} = 1;
	}
sub end_terminal   ( $self, $attributes={} ) {
	$self->{'in_terminal'} = 0;
	}

sub start_figure   ( $self, $attributes={} ) {
	$self->{in_figure} = 1;
	$self->{figure_title} = $attributes->{title};

	my $pad = $self->get_pad;
	}

sub end_figure {
	my( $self, $flags ) = @_;

	my $pad = $self->get_pad;
	my $filename = $self->{$pad};
	$self->clear_pad;

	$self->add_html_tag(
		"\n\n" .
		qq( <img src="$filename" /> ) .
		"\n\n" 
	
		);

	$self->{figure_title} = 0;
	$self->{in_figure} = 0;
	}
	
sub _get_initial_item_type ( $self, $attributes={} ) {
	my $type = $self->SUPER::_get_initial_item_type;

	$type;
	}

sub not_implemented ( $self, $attributes={} ) { croak "Not implemented! " . (caller(1))[3] }

sub in_item_list ( $self, $attributes={} ) { scalar @{ $self->{list_levels} } }
sub add_list_level_item ( $self, $attributes={} ) {
	${ $self->{list_levels} }[-1]{item_count}++;
	}
sub is_first_list_level_item ( $self, $attributes={} ) {
	${ $self->{list_levels} }[-1]{item_count} == 0;
	}

sub start_list_level ( $self, $attributes={} ) {
	push @{ $self->{list_levels} }, { item_count => 0 };
	}

sub end_list_level ( $self, $attributes={} ) {
	pop @{ $self->{list_levels} };
	}

sub start_item_bullet ( $self, $attributes={} ) {
	#print STDERR Dumper($self->{list_levels}), "\n"; use Data::Dumper;
	$self->add_html_tag( "</li>\n\n" )
		unless $self->is_first_list_level_item;
	$self->add_list_level_item;
	$self->add_html_tag( "<li>\n" );
	$self->start_Para;
	}

sub start_item_number ( $self, $attributes={} ) {
	$self->add_html_tag( '<li>' )
	}
sub start_item_block ( $self, $attributes={} )  { $self->add_html_tag( '<li>' ) }
sub start_item_text ( $self, $attributes={} )   { $self->add_html_tag( '<li>' ) }

sub end_item_bullet ( $self, $attributes={} ) {
	$self->end_Para;
#	$self->add_to_pad( "</listitem>\n\n" );
	$self->{in_item} = 0;
	}
sub end_item_number ( $self, $attributes={} ) { $self->add_html_tag( '</li>' ) }
sub end_item_block ( $self, $attributes={} )  { $self->add_html_tag( '</li>' ) }
sub end_item_text ( $self, $attributes={} )   { $self->add_html_tag( '</li>' ) }

sub start_over_bullet ( $self, $attributes={} ) {
	$self->add_html_tag( qq(<ol>) );
	$self->start_list_level;
	}

sub start_over_text   ( $self, $attributes={} )   { $self->add_html_tag( '<ol>' ) }
sub start_over_block  ( $self, $attributes={} )  { $self->add_html_tag( '<ol>' ) }
sub start_over_number ( $self, $attributes={} ) { $self->add_html_tag( '<ul>' ) }

sub end_over_bullet ( $self, $attributes={} ) {
	$self->{last_thingy}  = 'item_list';
	$self->end_non_code_text;
	$self->add_html_tag( "</li>\n\n" );

	# $self->add_to_pad( "</$tag>\n\n" ); XXX: WTF?
	$self->end_list_level;
	$self->emit;
	}

sub end_over_text   ( $self, $attributes={} )   {
	$self->add_html_tag( '</ul>' );
	$self->add_html_tag( '</ul>' )
	}
sub end_over_block  ( $self, $attributes={} )  {
	$self->add_html_tag( '</ul>' );
	$self->add_html_tag( '</ul>' )
	}
sub end_over_number ( $self, $attributes={} ) {
	$self->add_html_tag( '</ul>' );
	$self->add_html_tag( '</ul>' )
	}



sub end_B ( $self, $attributes={} )   { $self->add_html_tag( '</code>' ); $self->{in_B} = 0; }
sub start_B ( $self, $attributes={} ) {
	$self->add_html_tag( '<code class="command">' );
	$self->{in_B} = 1;
	}

sub end_C   ( $self, $attributes={} ) { $self->add_html_tag( '</code>' ); $self->{in_C} = 0; }
sub start_C ( $self, $attributes={} ) { $self->add_html_tag( '<code class="inline">' ); $self->{in_C} = 1; }

sub end_F   ( $self, $attributes={} ) { $self->add_html_tag( '</i>' ) }
sub start_F ( $self, $attributes={} ) { $self->add_html_tag( '<i class="filename">' )  }

sub end_I   ( $self, $attributes={} ) { $self->add_html_tag( '</em>' ) }
sub start_I ( $self, $attributes={} ) { $self->add_html_tag( '<em>' )  }

# keyword
sub end_K   ( $self, $attributes={} ) {
	my $text = $self->get_from_current_pad;
	$self->clear_pad;
	my $link = do {
		## what if it isn't a keyword??? XXX
			"http://perldoc.perl.org/function/$text.html"
		};

	$self->add_html_tag( qq|<a href class="keyword" src="$link">| );
	$self->add_to_pad( $text );
	$self->add_html_tag( '</a>' );
	$self->emit;
	$self->{in_K} = 0;
	}
	
sub start_K ( $self, $attributes={} ) { 	
	$self->emit;
	$self->{in_K} = 1;
 }

sub end_L   ( $self, $attributes={} ) {
	my $text = $self->get_from_current_pad;
	$self->clear_pad;
	my $link = do {
		if( $text =~ /\A(perl[a-z0-9]+)\z/ ) { "http://perldoc.perl.org/$1.html" }
		};

	$self->add_html_tag( qq|<a href class="external_link" src="$link">| );
	$self->add_to_pad( $text );
	$self->add_html_tag( '</a>' );
	$self->emit;
	$self->{in_L} = 0;
	}
sub start_L ( $self, $attributes={} ) {
	$self->emit;
	$self->{in_L} = 1;
	}

sub start_M ( $self, $attributes={} ) {
	$self->emit;
	$self->{'module_flag'} = 1;
	$self->{'module_text'} = '';
	}
sub end_M   ( $self, $attributes={} ) {
	my $text = $self->get_from_current_pad;
	$self->clear_pad;

	my $href = "https://www.metacpan.org/module/$text";

	$self->add_html_tag( qq(<a class="module" href="$href">) );
	$self->add_to_pad( $text );
	$self->add_html_tag( '</a>' );
	$self->clear_pad;

	$self->{'module_flag'} = 0;
	}

sub start_T ( $self, $attributes={} ) { $self->add_html_tag( '<i class="book_title">' )  }
sub end_T   ( $self, $attributes={} ) { $self->add_html_tag( '</i>' ) }

sub start_U ( $self, $attributes={} ) { $self->emit; $self->{in_U} = 1 }
sub end_U   ( $self, $attributes={} ) {
	my $text = $self->get_from_current_pad;
	$self->clear_pad;

	$self->add_html_tag( qq|<a href="$text" />| );
	$self->emit;
	$self->{in_U} = 0;
	}

sub handle_text ( $self, $text ) {
	my $pad = $self->get_pad;

	$self->escape_text( \$text );
	$self->{$pad} .= $text;

	unless( $self->dont_escape ) {
		$self->make_curly_quotes;
		$self->make_em_dashes;
		$self->make_ellipses;
		}
	}

sub dont_escape ( $self ) {
	$self->{in_verbatim} || $self->{in_C}
	}

sub escape_text ( $self, $text_ref ) {
	$$text_ref =~ s/&/&amp;/g;
	$$text_ref =~ s/</&lt;/g;

	return 1;
	}

sub make_curly_quotes ( $self ) {
	my $text  = $self->get_from_current_pad;

	require Tie::Cycle;

	tie my $cycle, 'Tie::Cycle', [ qw( &#x201C; &#x201D; ) ];

	1 while $text =~ s/"/$cycle/;

	# escape escape chars. This is escpaing them for InDesign
	# so don't worry about double escaping for other levels. Don't
	# worry about InDesign in the pod.
	$text =~ s/'/&#x2019;/g;

	$self->clear_pad;
	$self->add_to_current_pad( $text );

	return 1;
	}

sub make_em_dashes ( $self ) {
	my $pad  = $self->get_pad;
	$self->{$pad} =~ s/--/&#x2014;/g;
	return 1;
	}

sub make_ellipses ( $self ) {
	my $pad  = $self->get_pad;
	$self->{$pad} =~ s/\Q.../&#x2026;/g;
	return 1;
	}

BEGIN {
require Pod::Simple::BlackBox;

package Pod::Simple::BlackBox;

sub _ponder_Verbatim ( $self, $para ) {
	DEBUG and print STDERR " giving verbatim treatment...\n";

	$para->[1]{'xml:space'} = 'preserve';
	foreach my $line ( @$para[ 2 .. $#$para ] ) {
		$line =~ s/\A(\t|  )//gm;
		$line =~ s/\A(\t+)/" " x ( 4 * length($1) )/e;
		warn
			sprintf(
				"%s: tab in code listing! [%s]",
				$self->chapter,
				$line
				) if $line =~ /\t/;
  		}

  # Now the VerbatimFormatted hoodoo...
  if( $self->{'accept_codes'} and
      $self->{'accept_codes'}{'VerbatimFormatted'}
  ) {
    while(@$para > 3 and $para->[-1] !~ m/\S/) { pop @$para }
     # Kill any number of terminal newlines
    $self->_verbatim_format($para);
  } elsif ($self->{'codes_in_verbatim'}) {
    push @$para,
    @{$self->_make_treelet(
      join("\n", splice(@$para, 2)),
      $para->[1]{'start_line'}, $para->[1]{'xml:space'}
    )};
    $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
  } else {
    push @$para, join "\n", splice(@$para, 2) if @$para > 3;
    $para->[-1] =~ s/\n+$//s; # Kill any number of terminal newlines
  }
  return;
}

}

BEGIN {

# override _treat_Es so I can localize e2char
sub _treat_Es {
	my $self = shift;

	require Pod::Escapes;
	local *Pod::Escapes::e2char = *e2char_tagged_text;

	$self->SUPER::_treat_Es( @_ );
	}

sub e2char_tagged_text {
	package Pod::Escapes;

	my $in = shift;

	return unless defined $in and length $in;

	   if( $in =~ m/^(0[0-7]*)$/ )         { $in = oct $in; }
	elsif( $in =~ m/^0?x([0-9a-fA-F]+)$/ ) { $in = hex $1;  }

	if( $NOT_ASCII ) {
		unless( $in =~ m/^\d+$/ )
			{
			$in = $Name2character{$in};
			return unless defined $in;
			$in = ord $in;
	    	}

		return $Code2USASCII{$in}
			|| $Latin1Code_to_fallback{$in}
			|| $FAR_CHAR;
		}

 	if( defined $Name2character_number{$in} and $Name2character_number{$in} < 127 ) {
 		return "&$in;";
 		}
	elsif( defined $Name2character_number{$in} ) {
		# this needs to be fixed width because I want to look for
		# it in a negative lookbehind
		return sprintf '&#x%04x;', $Name2character_number{$in};
		}
	else
		{
		return '???';
		}

	}
}

=back

=head1 TO DO


=head1 SEE ALSO

L<Pod::PseudoPod>, L<Pod::Simple>

=head1 SOURCE AVAILABILITY

This source is in Github:

	http://github.com/briandfoy/pod-pseudopod-perltricks

If, for some reason, I disappear from the world, one of the other
members of the project can shepherd this module appropriately.

=head1 AUTHOR

brian d foy, C<< <bdfoy@cpan.org> >>

=head1 COPYRIGHT AND LICENSE

Copyright © 2014-2015, brian d foy <bdfoy@cpan.org>. All rights reserved.

You may redistribute this under the same terms as Perl itself.

=cut

sub _ponder_paragraph_buffer ( $self ) {

  # Para-token types as found in the buffer.
  #   ~Verbatim, ~Para, ~end, =head1..4, =for, =begin, =end,
  #   =over, =back, =item
  #   and the null =pod (to be complained about if over one line)
  #
  # "~data" paragraphs are something we generate at this level, depending on
  # a currently open =over region

  # Events fired:  Begin and end for:
  #                   directivename (like head1 .. head4), item, extend,
  #                   for (from =begin...=end, =for),
  #                   over-bullet, over-number, over-text, over-block,
  #                   item-bullet, item-number, item-text,
  #                   Document,
  #                   Data, Para, Verbatim
  #                   B, C, longdirname (TODO -- wha?), etc. for all directives
  #

  my $paras;
  return unless @{$paras = $self->{'paras'}};
  my $curr_open = ($self->{'curr_open'} ||= []);

  DEBUG > 10 and print "# Paragraph buffer: <<",  Pod::Simple::BlackBox::pretty($paras), ">>\n";

  # We have something in our buffer.  So apparently the document has started.
  unless($self->{'doc_has_started'}) {
    $self->{'doc_has_started'} = 1;

    my $starting_contentless;
    $starting_contentless =
     (
       !@$curr_open
       and @$paras and ! grep $_->[0] ne '~end', @$paras
        # i.e., if the paras is all ~ends
     )
    ;
    DEBUG and print "# Starting ",
      $starting_contentless ? 'contentless' : 'contentful',
      " document\n"
    ;

    $self->_handle_element_start('Document',
      {
        'start_line' => $paras->[0][1]{'start_line'},
        $starting_contentless ? ( 'contentless' => 1 ) : (),
      },
    );
  }

  my($para, $para_type);
  while(@$paras) {
    last if @$paras == 1 and
      ( $paras->[0][0] eq '=over' or $paras->[0][0] eq '~Verbatim'
        or $paras->[0][0] eq '=item' )
    ;
    # Those're the three kinds of paragraphs that require lookahead.
    #   Actually, an "=item Foo" inside an <over type=text> region
    #   and any =item inside an <over type=block> region (rare)
    #   don't require any lookahead, but all others (bullets
    #   and numbers) do.

# TODO: winge about many kinds of directives in non-resolving =for regions?
# TODO: many?  like what?  =head1 etc?

    $para = shift @$paras;
    $para_type = $para->[0];

    DEBUG > 1 and print "Pondering a $para_type paragraph, given the stack: (",
      $self->_dump_curr_open(), ")\n";

    if($para_type eq '=for') {
      next if $self->_ponder_for($para,$curr_open,$paras);
    } elsif($para_type eq '=begin') {
      next if $self->_ponder_begin($para,$curr_open,$paras);
    } elsif($para_type eq '=end') {
      next if $self->_ponder_end($para,$curr_open,$paras);
    } elsif($para_type eq '~end') { # The virtual end-document signal
      next if $self->_ponder_doc_end($para,$curr_open,$paras);
    }


    # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
    #~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
    if(grep $_->[1]{'~ignore'}, @$curr_open) {
      DEBUG > 1 and
       print "Skipping $para_type paragraph because in ignore mode.\n";
      next;
    }
    #~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
    # ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

    if($para_type eq '=pod') {
      $self->_ponder_pod($para,$curr_open,$paras);
    } elsif($para_type eq '=over') {
      next if $self->_ponder_over($para,$curr_open,$paras);
    } elsif($para_type eq '=back') {
      next if $self->_ponder_back($para,$curr_open,$paras);
    } elsif($para_type eq '=row') {
      next if $self->_ponder_row_start($para,$curr_open,$paras);

    } elsif( $para_type eq '=headrow'){
    	$self->start_headrow;
    } elsif( $para_type eq '=bodyrows') {
    	$self->start_bodyrows;
    	}

    else {
      # All non-magical codes!!!

      # Here we start using $para_type for our own twisted purposes, to
      #  mean how it should get treated, not as what the element name
      #  should be.

      DEBUG > 1 and print "Pondering non-magical $para_type\n";

      # In tables, the start of a headrow or bodyrow also terminates an
      # existing open row.
      if($para_type eq '=headrow' || $para_type eq '=bodyrows') {
        $self->_ponder_row_end($para,$curr_open,$paras);
      }

      # Enforce some =headN discipline
      if($para_type =~ m/^=head\d$/s
         and ! $self->{'accept_heads_anywhere'}
         and @$curr_open
         and $curr_open->[-1][0] eq '=over'
      ) {
        DEBUG > 2 and print "'=$para_type' inside an '=over'!\n";
        $self->whine(
          $para->[1]{'start_line'},
          "You forgot a '=back' before '$para_type'"
        );
        unshift @$paras, ['=back', {}, ''], $para;   # close the =over
        next;
      }


      if($para_type eq '=item') {
        next if $self->_ponder_item($para,$curr_open,$paras);
        $para_type = 'Plain';
        # Now fall thru and process it.

      } elsif($para_type eq '=extend') {
        # Well, might as well implement it here.
        $self->_ponder_extend($para);
        next;  # and skip
      } elsif($para_type eq '=encoding') {
        # Not actually acted on here, but we catch errors here.
        $self->_handle_encoding_second_level($para);

        next;  # and skip
      } elsif($para_type eq '~Verbatim') {
        $para->[0] = 'Verbatim';
        $para_type = '?Verbatim';
      } elsif($para_type eq '~Para') {
        $para->[0] = 'Para';
        $para_type = '?Plain';
      } elsif($para_type eq 'Data') {
        $para->[0] = 'Data';
        $para_type = '?Data';
      } elsif( $para_type =~ s/^=//s
        and defined( $para_type = $self->{'accept_directives'}{$para_type} )
      ) {
        DEBUG > 1 and print " Pondering known directive ${$para}[0] as $para_type\n";
      } else {
        # An unknown directive!
        DEBUG > 1 and printf "Unhandled directive %s (Handled: %s)\n",
         $para->[0], join(' ', sort keys %{$self->{'accept_directives'}} )
        ;
        $self->whine(
          $para->[1]{'start_line'},
          "Unknown directive: $para->[0]"
        );

        # And maybe treat it as text instead of just letting it go?
        next;
      }

		DEBUG > 1 and print "para_type is $para_type\n";
      if($para_type =~ s/^\?//s) {
        if(! @$curr_open) {  # usual case
          DEBUG and print "Treating $para_type paragraph as such because stack is empty.\n";
        } else {
          my @fors = grep $_->[0] eq '=for', @$curr_open;
          DEBUG > 1 and print "Containing fors: ",
            join(',', map $_->[1]{'target'}, @fors), "\n";

          if(! @fors) {
            DEBUG and print "Treating $para_type paragraph as such because stack has no =for's\n";

          #} elsif(grep $_->[1]{'~resolve'}, @fors) {
          #} elsif(not grep !$_->[1]{'~resolve'}, @fors) {
          } elsif( $fors[-1][1]{'~resolve'} ) {
            # Look to the immediately containing for
			DEBUG and print "~resolve is $fors[-1][1]{'~resolve'}\n";

            if($para_type eq 'Data') {
              DEBUG and print "Treating Data paragraph as Plain/Verbatim because the containing =for ($fors[-1][1]{'target'}) is a resolver\n";
              $para->[0] = 'Para';
              $para_type = 'Plain';
            } else {
              DEBUG and print "Treating $para_type paragraph as such because the containing =for ($fors[-1][1]{'target'}) is a resolver\n";
            }
          } else {
            DEBUG and print "Treating $para_type paragraph as Data because the containing =for ($fors[-1][1]{'target'}) is a non-resolver\n";
            $para->[0] = $para_type = 'Data';
          }
        }
      }

      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      if($para_type eq 'Plain') {
        $self->_ponder_Plain($para);
      } elsif($para_type eq 'Verbatim') {
        $self->_ponder_Verbatim($para);
      } elsif($para_type eq 'Data') {
        $self->_ponder_Data($para);
      } else {
        die "\$para type is $para_type -- how did that happen?";
        # Shouldn't happen.
      }

      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      $para->[0] =~ s/^[~=]//s;

      DEBUG and print "\n", Pod::Simple::BlackBox::pretty($para), "\n";

      # traverse the treelet (which might well be just one string scalar)
      $self->{'content_seen'} ||= 1;
      $self->_traverse_treelet_bit(@$para);
    }
  }

  return;
}

1;
