package Pod::WikiText;

=begin wiki

!1 Pod Punch List

!2 Tests

The test harness has to be modified so it can ignore specific lines (lines \
with dates for example).

!2 Format Option

* /V/ html
* /V/ text
* /V/ reference
* /V/ codetext
* /V/ codehtml

!2 Additional Options

* /V/ section
* /V/ infile
* /V/ outfile
* /V/ author
* /V/ title
* /V/ useheader
* /V/ header
* /V/ usefooter
* /V/ footer
* /V/ toc
* /V/ navigation
* /V/ borders
* /V/ wrapcol
* /V/ codelabels
* /V/ language
* /V/ startinpod
* /V/ linkback
* /V/ debug

!2 Current Enhancements

* /V/ Html header and footer
* /V/ Genearate a Table of Contents
* /V/ Syntax Highlighting of code blocks
* /V/ Insert space into table cells for better padding
* /V/ Allow cells which contain a period in column one to be empty cells
* /V/ Allow line breaking inside of table cells
* /V/ Allow global document setting of table borders
* /V/ Support for <nul> replacement after Tiki markup
* /V/ Support for borders/noborders within table source
* /V/ Support for linkback html at beginning of document
* /V/ Variable substitution in document header and footer
* /V/ Provided a full complement of "setters"
* /V/ Add support for table row background color
* /V/ Add support for table cell background color
* /V/ Correct problem where table is followed immediately by <hr>
* /V/ Support use of an svg "checkmark" image

/V/ = Latin for Veritas, or "truth", signifying the item has been completed.

!2 Support Scripts

* wthtml.pl
* wttext.pl
* wtreference.pl
* wtcodetext.pl
* wtcodehtml.pl

These will gather the appropriate command line parameters. Provide format \
specific help, and invoke Pod::WikiText for that particular format type.

These utilities also provide conf file storage for their respective defaults.

!2 Documentation

* Show this table for all options that are specific to only certain table \
types, just give a list of the others.

|*format* |*option1*|*option2*|*option3*|*option4*|
|html     |yes      |no       |yes      |no       |
|text     |yes      |no       |yes      |no       |
|reference|yes      |no       |yes      |no       |
|codetext |yes      |no       |yes      |no       |
|codehtml |yes      |no       |yes      |no       |

!2 Tests

Write tests for each output format. Write tests for each option. Write tests \
for all subroutines not covered by the above tests.

!2 Future Enhancements

* Allow user specified ignore "meta tags"
* Allow optional custom style sheet (external style sheet)
* Allow optional background image (format html only)

----

!1 NAME

Pod::WikiText.pm

Support for Wiki markup in POD.

----

!1 SYNOPSIS

 % language=Perl
 % use Pod::WikiText;
 %
 % my $formatter = Pod::WikiText->new( format  => 'html',
 %                                     author  => 'Brad Adkins',
 %                                     infile  => 'test.pl',
 %                                     outfile => 'stdout'
 %                                     title   => 'Example'
 %                                   );
 % $formatter->format;
 %%

You can create multiple Pod::WikiText objects if needed.

----

!1 RATIONALE

Provided an alternative for documentation of Perl source files which allows \
the use of a robust flavor of Wiki markup in place of POD markup. This \
allows the creation of more expressive POD in your Perl source files, and \
hence better documentation when published.

----

!1 DESCRIPTION

POD sections in source files are marked in the standard way with 'begin' \
and 'cut' tags. The 'begin' tag must be followed by the keyword 'wiki', as in: \
"=begin wiki". (See this source file for examples.)

This module can be used for many purporses beyond Perl source documentation. \
Presentations and other forms of documentaiton are candiates for use. This is \
possible because the markup support provided by the Text::Tiki module is very \
good, and several options are provided by Pod::WikiText specifically with \
general documentation purposes in mind.

----

!1 OPTIONS

The primary option is the /format/ option. This options is used to select the \
output format.

Usage: -format=/option_value/

|*option values*|*description*|
|/html/         | Output embedded pod as html|
|/text/         | Output embedded pod as text|
|/slideshow/    | Output embedded pod as html slideshow|
|/reference/    | Output embedded pod and code as html|
|/codetext/     | Output code as text|
|/codehtml/     | Output code as html|

The remaining options are used to tailor the output generated by the selected \
format.

----

!1 AUTOMATION

To process multiple files, you simply create a new WikiText object for each \
file. Something like this should suffice.

 % language=Perl
 % foreach my $file ( @files ) {
 %     my $formatter = Pod::WikiText->new( format  => 'html',
 %                                         author  => 'Brad Adkins',
 %                                         infile  => $file,
 %                                         outfile => 'stdout'
 %                                         title   => 'Example'
 %                                       );
 %     $formatter->format;
 %     undef $formatter;
 % }
 %%

Using undef on the old WikiText object saves a small amount of memory when \
creating multiple objects.

----

!1 WIKI MARKUP

Pod::WikiText uses the Text::Tiki module for base markup processing. Please \
refer to the POD in that module for additional details and explanation of the \
markup capabilities provided by Text::Tiki.

----

!1 ADDITIONAL MARKUP

Several customizations to the Tiki html output are implemented in this module.

/*Genearating a Table of Contents*/

If the 'toc' parameter is set to 'yes' when creating a new Pod::WikiText \
object, a Table of Contents will be inserted at the beginning of the html \
output. Level 1 thru level 4 headings in the source document will generate \
entries in the Table of Contents.

/*Syntax highlighting of code blocks*/

Code blocks prefaced with ' % ' starting in column 1 will be syntax highlighted. \
You will need to install the Syntax::Highlight::Engine::Kate module. This module \
provides syntax highlighting as implemented in the Kate text editor.

The first line of a code block to be highlighted is a command that tells the
highlighter what language to use, here is an example for Perl.

 % language=Perl
 % if ( $self->{_toc} ) {
 %     $html = $self->create_toc . $html;
 % }
 %%

/*Insert non-breaking space into table cells for better padding*/

Non-breaking spaces are added around cell contents to provide visual appeal.

/*Allow cells which contain a period in column one to be empty cells*/

This:

 |col1|col2 is longer|col3|
 |col1|.|col3|
 |.|col2|col3 is longer too|

Will produce:

|col1|col2 is longer|col3|
|col1|.|col3|
|.|col2|col3 is longer too|

/*Allow line breaks inside table cells*/

Allow a line break within a table cell using the break macro '##BR##'.

This:

 |col1|col2 is longer|col3|
 |col1|col2|col3|
 |col1|col2|col3 is longer too##BR##And has multiple##BR##lines of text|

Will produce:

|col1|col2 is longer|col3|
|col1|col2|col3|
|col1|col2|col3 is longer too##BR##And has multiple##BR##lines of text|

/*Add support for table borders*/

Use the parameter 'borders' when creating Pod::WikiText objects to control the \
use of borders on all html tables.

/* Add support for table borders on a table-by-table basis*/

Allow borders to be defined for individual tables using the border macros \
'##BORDER 0##' and '##BORDER 1##' for no borders and borders, respectively.

This:

Will produce:

/*Add support for table row background color*/

Allow a table row to have a specified background color using the macro \
'##BGxxxxxx###', where 'xxxxxx' is a hex color code.

This:

Will produce:

----

!1 META TAGS

Pod::WikiText supports several meta tags that can be used in source files for \
various purposes.

The first set of meta tags are used to support source files maintained using \
the Foldmaster programmer's editor (http://foldmaster.de). These tags are used \
by Foldmaster to indicate explicit folds within the source file. These are:

| *Meta Tag*     |*Description*|
| %##{{{%        |start fold in .pl and .pm files|
| %##}}}%        |end fold in .pl and .pm files|
| %(*{{{%        |start fold in .wiki and .txt files|
| %(*}}}%        |end fold in lwiki and .txt files|

The second set of meta tags can be inserted in the source document to provide \
file specific options. These tags must begin in column 1.

| *Meta Tag*     |*Description*|
| %##file:%      |file name (not used at this time)|
| %##dir:%       |file path (not used at this time)|
| %##remote:%    |remote path (not used at this time)|
| %##clearcase:% |ClearCase path (not used at this time)|
| %##head:%      |header (overrides header parameter)|
| %##foot:%      |footer (overrides footer parameter)|
| %##url:%       |for web browser invocation|
| %##publish:%   |for publishing generated html|
| %##author:%    |for the html header|
| %##title:%     |for the html header|

These are all tags recognized in the source file when processed. Those not \
yet implemented are simply ignored.

----

=cut

use strict;
use warnings;
use Carp;
use Cwd;
use File::Spec;
use Text::Wrap;
use Text::Tiki;
use Syntax::Highlight::Engine::Kate;

our $VERSION = "0.01";
our $PROGRAMNAME = "WikiText";

my (%docinfo,@aotoc,%hotoc,@inpod,@lines,@format,@nonformat);
my $debug = 0;
my $sysdate = localtime();
$sysdate =~ s/ \d\d:\d\d:\d\d/,/;
$sysdate =~ s/  / /g;
my @file_management_keys = (
    "file","directory","clearcase","ftp","publish","url"
);
my @object_param_keys = (
    "format","section","infile","outfile","author","title","header","useheader",
    "footer","usefooter","toc","navigation","borders","wrapcol","codelabels",
    "usesvg","language","startinpod","linkback","debug"
);

=begin wiki

!1 METHODS

!2 Public Methods

!3 Method new

/Parameters/

The constructor method supports the following named arguments.

|*Parameter*  |*Default*    |*Value*|
|%format%     |required     |valid opiton ^1^|
|%section%    |none         |a level 1 heading|
|%infile%     |required     |filename|
|%outfile%    |required     |filename|
|%author%     |none         |html meta author|
|%title%      |none         |html title|
|%header%     |none         |WikiText markup|
|%useheader%  |no           |yes/no|
|%footer%     |basic footer |WikiText markup|
|%usefooter%  |yes          |yes/no|
|%toc%        |yes          |yes/no|
|%navigation% |no           |yes/no|
|%borders%    |yes          |yes/no|
|%wrapcol%    |72           |numeric|
|%codelabels% |yes          |yes/no|
|%usesvg%     |yes          |yes/no|
|%startinpod% |no           |yes/no|
|%linkback%   |none         |html|
|%debug%      |no           |yes/no|

^1^ Valid format options: html, text, reference, codetext, codehtml

/Description/

This is the class constructor. Use this method to create new Pod::WikiText \
objects.

/Test/

%insert name of test script here%

=cut

sub new {
    my ($class, %arg) = @_;

    my $sig = "<p><em>Created using $PROGRAMNAME, Version $VERSION<br>$sysdate</em></p>";

    my $podwikitext = bless {
        _format     => lc($arg{format})     || "html",
        _section    => $arg{section}        || '',
        _infile     => $arg{infile}         || croak("no infile given"),
        _outfile    => $arg{outfile}        || "stdout",
        _author     => $arg{author}         || '',  ## for html head
        _title      => $arg{title}          || '',  ## for html head
        _header     => $arg{header}         || '',
        _useheader  => lc($arg{useheader})  || "no",
        _footer     => $arg{footer}         || $sig,
        _usefooter  => lc($arg{usefooter})  || "yes",
        _toc        => lc($arg{toc})        || "yes",
        _navigation => lc($arg{navigation}) || "no",
        _borders    => lc($arg{borders})    || "yes",
        _wrapcol    => $arg{wrapcol}        || 72,
        _codelabels => lc($arg{codelabels}) || "yes",
        _usesvg     => lc($arg{usesvg})     || "yes",
        _language   => $arg{language}       || "Perl",
        _startinpod => lc($arg{startinpod}) || "no",
        _linkback   => $arg{linkback}       || "<!-- no linkback provided -->",
        _debug      => lc($arg{debug})      || "no",
    }, $class;

    croak("param 'format' invalid")     unless $podwikitext->{_format} =~ /html|text|reference|codetext|codehtml/;
    croak("param 'infile' not found")   unless -e $podwikitext->{_infile};
    croak("param 'useheader' invalid")  unless $podwikitext->{_useheader} =~ /yes|no/;
    croak("param 'usefooter' invalid")  unless $podwikitext->{_usefooter} =~ /yes|no/;
    croak("param 'toc' invalid")        unless $podwikitext->{_toc} =~ /yes|no/;
    croak("param 'navigation' invalid") unless $podwikitext->{_navigation} =~ /yes|no/;
    croak("param 'borders' invalid")    unless $podwikitext->{_borders} =~ /yes|no/;
    croak("param 'codelabels' invalid") unless $podwikitext->{_codelabels} =~ /yes|no/;
    croak("param 'usesvg' invalid")     unless $podwikitext->{_usesvg} =~ /yes|no/;
    croak("param 'startinpod' invalid") unless $podwikitext->{_startinpod} =~ /yes|no/;
    croak("param 'debug' invalid")      unless $podwikitext->{_debug} =~ /yes|no/;

    ## may also be specified in the source document
    $docinfo{author} = $podwikitext->{_author};
    $docinfo{title} = $podwikitext->{_title};
    $docinfo{linkback} = $podwikitext->{_linkback};

    $podwikitext->{_bordertype} = 'hidden';
    if ( $podwikitext->{_borders} eq "yes" ) {
        $podwikitext->{_bordertype} = 'solid';
    }

    if ( $podwikitext->{_debug} eq 'yes' ) { $debug = 1; }  ## turn debug on

    return $podwikitext;
}

=begin wiki

!3 Method get_param

/Parameters/

* %$self% - reference to our object
* %$key% - the parameter name

/Description/

Return the value associated with parameter $key.

/Test/

%insert name of test script here%

=cut

sub get_param {
    my ($self, $ukey) = @_;
    my $val = '';

    my $key = '_'.$ukey;
    if ( defined $self->{$key} ) { $val = $self->{$key}; }
    return $val;
}

=begin wiki

!3 Method set_param

/Parameters/

* %$self% - reference to our object
* %$key% - the parameter name
* %$val% - the value to use

/Description/

Set a new value for the parameter $key using value $val.

/Test/

%insert name of test script here%

=cut

sub set_param {
    my ($self, $ukey, $val) = @_;

    my $key = '_'.$ukey;
    if ( is_valid_param( $key ) ) {
        $self->{$key} = $val;
    } else {
        $val = '';
    }
    return $val;
}

=begin wiki

!3 Method get_sections

/Parameters/

* %$self% - reference to our object

/Description/

Return a list of all the level one heading titless contained within the \
current document.

/Test/

%insert name of test script here%

=cut

sub get_sections {
    my $self = shift;
    my @sections;

    $self->read_input;

    foreach my $toce ( @aotoc ) {
        my $title = $toce->{line};
        next unless $toce->{line} =~ /^!1 /;
        $title =~ s/^![1-4]{1,1} //;
        push @sections, $title;
    }

    return @sections;
}

=begin wiki

!3 Method set_section

/Parameters/

* %$self% - reference to our object
* %$section% - Title of section to set

/Description/

Set the section title to the desired title.

/Test/

%insert name of test script here%

=cut

sub set_section {
    my ($self,$section) = @_;
    $self->{_section} = $section;
    return 0;
}

=begin wiki

!3 Method is_section

/Parameters/

* %$self% - reference to our object
* %section% - A level one heading to verify

/Description/

Verify that the level one heading provided exists in the current document.

/Test/

%insert name of test script here%

=cut

sub is_section {
    my ($self,$section) = @_;

    $self->read_input;

    my $found = 0;
    foreach my $toce ( @aotoc ) {
        my $title = $toce->{line};
        if ( $toce->{line} =~ /^!1 / ) {;
            $title =~ s/^!1 //;
            if ( $title eq $section ) {
                $found = 1;
                last;
            }
        }
    }

    return $found;
}

=begin wiki

!3 Method format

/Parameters/

* %$self% - reference to our object

/Description/

/Test/

%insert name of test script here%

=cut

sub format {
    my $self = shift;

    $self->read_input;
    if ( $debug ) { $self->debug_read; }

    if ( $self->{_format} eq "html" ) {
        $self->format_html;
    }
    if ( $self->{_format} eq "text" ) {
        $self->format_text;
    }
    if ( $self->{_format} eq "reference" ) {
        $self->format_reference;
    }
    if ( $self->{_format} eq "codetext" ) {
        $self->format_codetext;
    }
    if ( $self->{_format} eq "codehtml" ) {
        $self->format_codehtml;
    }
}

=begin wiki

!2 Private Methods

/Test/

%insert name of test script here%

!3 Function is_valid_param

/Parameters/

* %$key% - paramater to check

/Description/

Check object supplied value to see if it is a valid object paramter.

/Test/

%insert name of test script here%

=cut

sub is_valid_param {
    my $key = shift;

    $key =~ s/^_//;
    if ( $key =~ /format|section|infile|outfile|author|title|header|useheader|
                  footer|usefooter|toc|navigation|borders|wrapcol|startinpod|
                  linkback|debug/x ) {
        return 1;
    }
    return 0;
}

=begin wiki

!3 Function init_stores

/Parameters/

None

/Description/

Initialize module level data stores to empty state.

/Test/

%insert name of test script here%

=cut

sub init_stores {
    my $self = shift;

    @aotoc = ();
    %hotoc = ();
    @inpod = ();
    @lines = ();
    @format = ();
    @nonformat = ();

    return 0;
}

=begin wiki

!3 Function read_input

/Parameters/

* %$self% - reference to our object

Sets:

* %@lines% - all lines from input file
* %@aotoc% - array of header line information
* %@hotoc% - hash of header line information
* %@inpod% - flags indicating pod or non-pod line

/Description/

Read the contents of the file into three arrays. These arrays form the raw \
data for input to Text::Tiki.

/Test/

%insert name of test script here%

=cut

sub read_input {
    my $self = shift;

    my $infile = $self->{_infile};

    $self->init_stores;

    my $inpod = 0;

    my $beginfold = '^beginfold\{\{\{';  ## default
    my $endfold   = '^endfold\}\}\}';    ## default

    ## initialize source editor meta tags
    if ( $infile =~ /\.pl$|\.pm$/ ) {  ## recognize Foldmaster 'source' files
        $beginfold = '^\#{1,2}\{\{\{';
        $endfold = '^\#{1,2}\}\}\}';
        $inpod = 0;
    }
    if ( $infile =~ /\.txt$|\.wiki$/ ) {  ## recognize Foldmaster 'text' files
        $beginfold = '^\(\*\{\{\{';
        $endfold = '^\(\*\}\}\}';
        $inpod = 1;
    }

    if ( $self->{_startinpod} eq "yes" ) {
        $inpod = 1;
    }

    my $line = '';    ## line continuation buffer
    my $linenum = 0;  ## current line number
    my $prevtoc = 0;  ## previous toc entry

    open(my $fh, "<", $infile) or die "unable to open $infile";
    while ( <$fh> ) {
        chomp;

        ## check for source editor meta tags
        if ( /$beginfold/ ) {
            push @lines, "";
            next;
        }
        if ( /$endfold/   ) {
            ##push @lines, "";
            next;
        }

        ## depricated tags
        if ( /^\#\#(\@\@|\$\$|\/\/)/ ) {  ##@@, @@$$ ##// are depricated
            next;
        }

        ## comment tag
        if ( /^\#\#:/ ) {  ##: is a comment tag
            next;
        }

        ## load document information from meta tags
        if ( /^\#\#([a-z]+):(.*)/ ) {
            my $key = $1;
            my $val = $2;
            $val =~ s/\s+$//;
            $docinfo{$key} = $val;
            next;
        }

        ## check for pod status
        if ( /^=begin wiki/ ) { $inpod = 1; next; }  ## =cut
        if ( /^=cut/ ) { $inpod = 0; next; }

        ## save headings information
        if ( /^!([1-4]{1,1}) / ) {
            my $toc_entry = $_;
            my $toc_level = $1;
            my $id = $_;
            $id =~ s/^![1-4]{1,1} //;     ## remove header markup
            $id =~ s/[^\s\w\d]+//g;       ## remove non alpha/ws characters
            $id =~ s/\b([a-z])/\u\L$1/g;  ## proper case
            $id =~ s/\s+//g;              ## remove whitespace
            push @aotoc, {  ## array of toc entries
                line    => $toc_entry,
                anchor  => $id,
                level   => $toc_level,
            };
            my $key = sprintf("%05d", $linenum);
            if ( $toc_level == 1 ) {  ## hash of level 1 toc entries
                $hotoc{$key} = {
                    line    => $toc_entry,
                    anchor  => $id,
                    prevtoc => $prevtoc,
                    nexttoc => 0,
                };
                $prevtoc = $key;
            }
            push @lines, $key.':'.$toc_entry;  ## "key" the heading
            push @inpod, $inpod;
            $linenum++;
            next;
        }

        ## store the line or cat to line continuation buffer
        $line .= $_;
        if ( /\\$|\\\s+$/ ) {  ## line continuation found
            $line =~ s/\\\s+$/ /;    ## replace \ + ws
            $line =~ s/\s+\\\n$/ /;  ## replace ws + \ + \n
            $line =~ s/\s+\\$/ /;    ## replace ws + \
            next;
        } else {
            push @lines, $line;
            push @inpod, $inpod;
            $line = '';
            $linenum++;
        }
    }
    close $fh;

    ## finish headings linked list
    foreach my $toc ( reverse sort keys %hotoc ) {
        my $prevtoc = $hotoc{$toc}{prevtoc};
        if ( $prevtoc > 0 ) {
            $hotoc{$prevtoc}{nexttoc} = $toc;
        }
    }

    ## update object params from doc info, all params are fair game
    foreach my $key ( keys %docinfo ) {
        $key = lc($key);
        $self->{'_'.$key} = $docinfo{$key};
    }

    if ( $self->{_debug} eq "yes" ) { $self->debug_params; }

    return 0;
}

=begin wiki

!3 Function format_html

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub format_html {
    my $self = shift;

    if ( $self->{_section} ) {
        $self->prep_html_section;
    } else {
        $self->prep_html;
    }
    if ( $debug ) { $self->debug_prep; }

    my $formatter = Text::Tiki->new;
    my $html = $formatter->format(\@format);

    if ( ( $self->{_toc} eq "yes" ) && ( ! $self->{_section} ) ) {
        $html = $self->create_toc . $html;
    }

    $self->post_process( \$html );
    $self->output_format( \$html );

    return 0;
}

=begin wiki

!3 Function format_text

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub format_text {
    my $self = shift;

    if ( $self->{_section} ) {
        $self->prep_html_section;
    } else {
        $self->prep_html;
    }
    if ( $debug ) { $self->debug_prep; }

    $self->text_wrap( \@format );
    my $text = join "\n", @format;
    $self->output_format( \$text );

    return 0;
}

=begin wiki

!3 Function format_reference

/Parameters/

* %$self% - reference to our object

/Description/

This function uses both the @format array and the @nonformat array to build a \
new array of lines to be submitted to the Tiki formatter. Lines in the @nonformat \
array have the 'preformat' string appended to the start of each line. Each \
section of non-pod has a language tag inserted at the beginning of the section. \
The default language is 'Perl', but this can be controlled by the user as a \
parameter when the Pod::WikiText object is created. The key to combining both \
input sources is the @inpod array.

/Test/

%insert name of test script here%

=cut

sub format_reference {
    my $self = shift;

    $self->prep_html;
    if ( $debug ) { $self->debug_prep; }

    my $language = $self->{_language};
    my @rformat = ();
    my $podblock = 1;
    my $line;
    my $i = 0;
    foreach my $ispod ( @inpod ) {
        if ( $ispod++ ) {
            if ( ! $podblock ) {  ## entering first line of pod block
                push @rformat, " %%";  ## end previous code block
                push @rformat, "";
                push @rformat, "/end code block/";
                push @rformat, "";
                $podblock = 1;
            }
            $line = shift @format;
            push @rformat, $line;
        } else {
            if ( $podblock ) {  ## entering first line of code block
                push @rformat, "";  ## start a new code block
                push @rformat, "/begin code block/";
                push @rformat, "";
                push @rformat, " % language=$language";
                $podblock = 0;
            }
            $line = shift @nonformat;
            push @rformat, " % $line";
        }
    }

    if ( ! $podblock ) {
        push @rformat, " %%";  ## end previous code block
        push @rformat, "";
        push @rformat, "/end code block/";
        push @rformat, "";
    }

    my $formatter = Text::Tiki->new;
    my $html = $formatter->format(\@rformat);

    if ( $self->{_toc} ) {
        $html = $self->create_toc . $html;
    }

    $self->post_process( \$html );
    $self->html_codeblock_tags( \$html );
    $self->output_format( \$html );

    return 0;
}

=begin wiki

!3 Function format_codetext

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub format_codetext {
    my $self = shift;

    if ( $self->{_section} ) {
        $self->prep_html_section;
    } else {
        $self->prep_html;
    }
    if ( $debug ) { $self->debug_prep; }

    my $text = join "\n", @nonformat;
    $self->output_format( \$text );

    return 0;
}

=begin wiki

!3 Function format_codehtml

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub format_codehtml {
    my $self = shift;

    if ( $self->{_section} ) {
        $self->prep_html_section;
    } else {
        $self->prep_html;
    }
    if ( $debug ) { $self->debug_prep; }

    my @html = map { " % " . $_ . "\n" } @nonformat;
    my $language = " % language=" . $self->{_language} . "\n";
    unshift @html, $language;
    push @html, " %%\n";

    my $html = join "", @html;

    $self->html_syntax_highlight( \$html );
    $self->output_format( \$html );

    return 0;
}

=begin wiki

!3 Function prep_html

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub prep_html {
    my $self = shift;

    @format = ();
    @nonformat = ();
    my $i = 0;
    foreach my $line ( @lines ) {
        if ( $inpod[$i++] ) {
            if ( $line =~ /^(\d{5,5}):!(\d){1,1} / ) {  ## level 1 heading
                my $key = $1;
                my $level = $2;
                $line =~ s/^\d{5,5}://;
                if ( $level == 1 && $self->{_navigation} eq "yes" ) {  ## insert nav line
                    push @format, $line;
                    push @format, ' ';

                    my $nextlink = "Next";
                    my $prevlink = "Prev";
                    my $nextkey = $hotoc{$key}{nexttoc};
                    my $prevkey = $hotoc{$key}{prevtoc};
                    if ( $nextkey > 0 ) {
                        my $nextanchor = "#".$hotoc{$nextkey}{anchor};
                        $nextlink = "[Next]:$nextanchor";
                    }
                    if ( $prevkey > 0 ) {
                        my $prevanchor = "#".$hotoc{$prevkey}{anchor};
                        $prevlink = "[Prev]:$prevanchor";
                    }
                    push @format, "$prevlink | $nextlink | [Index]:#WikiIndex00000";
                    next;
                }
            }
            push @format, $line;
        } else {
            push @nonformat, $line;
        }
    }

    return 0;
}

=begin wiki

!3 Function prep_html_section

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub prep_html_section {
    my $self = shift;

    my $section = '!1 ' . $self->{_section};
    my $insection = 0;

    @format = ();
    my $i = 0;
    foreach my $line ( @lines ) {
        if ( $inpod[$i++] ) {
            if ( $line =~ /^(\d{5,5}):!(\d){1,1} / ) {  ## level 1 heading
                my $key = $1;
                my $level = $2;
                $line =~ s/^\d{5,5}://;
                if ( $level == 1 && $line eq $section ) {
                    $insection = 1;
                    push @format, $line;
                    push @format, ' ';
                    next;
                }
                if ( $level == 1 && $insection ) {
                    last;
                }
            }
            if ( $insection ) { push @format, $line; }
        }
    }

    return 0;
}

=begin wiki

!3 Function post_process

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the generated html

/Description/

=cut

sub post_process {
    my ($self, $html) = @_;

    if ( $self->{_useheader} ) {
        $self->header_vars;
        $$html = $self->{_header} . $$html;
    }
    if ( $self->{_usefooter} ) {
        $self->footer_vars;
        $$html .= $self->{_footer};
    }

    $self->html_add_cell_spacing( $html );
    $self->html_pad_empty_cells( $html );
    $self->html_insert_checkmarks( $html );
    $self->html_insert_line_breaks( $html );
    $self->html_set_borders( $html );
    $self->html_set_bgcolors( $html );
    $self->html_replace_nul( $html );
    $self->html_fixes( $html );
    $self->html_syntax_highlight( $html );
    $self->html_add_header( $html );
    $self->html_add_footer( $html );

    return 0;
}

=begin wiki

!3 Function output_format

/Parameters/

* %$self% - reference to our object - object
* %$output% - reference to output lines

/Description/

Write to file.

=cut

sub output_format {
    my ($self, $output) = @_;

    my $outfile = $self->{_outfile};
    if ( $outfile =~ /stdout/i ) {
        print $$output;
    } else {
        open(my $fh, ">", $outfile) or die "unable to open $outfile";
        print $fh $$output;
        close $fh;
    }

    return 0;
}

=begin wiki

!3 Function create_toc

/Parameters/

* %$self% - reference to our object

/Description/

Create table of contents html based on entries stored in the @aotoc array.

/Test/

%insert name of test script here%

=cut

sub create_toc {
    my $self = shift;

    my $plevel = 0;
    my $indent = 0;
    my $i = 0;
    my @toclines;

    my $beginlist = '<ul>';
    my $endlist = '</ul>';

    push @toclines, "<!-- INDEX -->";
    foreach my $toce ( @aotoc ) {
        my $line = $toce->{line};
        $line =~ s/^![1-4]{1,1} //;  ## remove wiki markup
        my $anchor = $toce->{anchor};
        my $level = $toce->{level};

        if ( $level > $plevel ) {
            my $ntags = $level - $plevel;
            for (my $i=1; $i<=$ntags; $i++) {
                push @toclines, ' ' x ($level * 2) . $beginlist;
            }
            push @toclines, ' ' x ($level * 2) . "<li><a href=\"#$anchor\">$line</a></li>";
        }
        if ( $level == $plevel ) {
            push @toclines, ' ' x ($level * 2) . "<li><a href=\"#$anchor\">$line</a></li>";
        }
        if ( $level < $plevel ) {
            my $ntags = $plevel - $level;
            for (my $i=1; $i<=$ntags; $i++) {
                push @toclines, ' ' x ($level * 2) . $endlist;
            }
            push @toclines, ' ' x ($level * 2) . "<li><a href=\"#$anchor\">$line</a></li>";
        }
        ## next iteration
        $plevel = $level;
        $i++;
    }
    for (my $i=$plevel; $i>0; $i--) {
        push @toclines, ' ' x ($i * 2) . $endlist;
    }
    push @toclines, "<!-- INDEX -->";
    push @toclines, "<hr />";

    return join("\n", @toclines);
}

=begin wiki

!3 Function debug_read

/Parameters/

None

/Description/

This function is used to dump the contents of @lines, @aotoc, %hotoc, and \
@inpod to individual files for inspection.

=cut

sub debug_read {
    my $self = shift;
    my ($db, $i);

    $i = 0;
    my $file = "_debug_lines.debug";
    open($db, ">", $file) or die "unable to open $file";
    foreach my $line ( @lines ) {
        print $db $line, "\n";
    }
    close($db);

    $i = 0;
    $file = "_debug_aotoc.debug";
    open($db, ">", $file)   or die "unable to open $file";
    foreach my $toc ( @aotoc ) {
        print $db "line   :";
        print $db $toc->{line}, "\n";
        print $db "anchor :";
        print $db $toc->{anchor}, "\n";
        print $db "level  :";
        print $db $toc->{level}, "\n";
        $i++;
    }
    close($db);

    $i = 0;
    $file = "_debug_hotoc.debug";
    open($db, ">", $file)   or die "unable to open $file";
    foreach my $toc ( sort keys %hotoc ) {
        print $db "key    :";
        print $db $toc, "\n";
        print $db "line   :";
        print $db $hotoc{$toc}{line}, "\n";
        print $db "anchor :";
        print $db $hotoc{$toc}{anchor}, "\n";
        print $db "prevtoc:";
        print $db $hotoc{$toc}{prevtoc}, "\n";
        print $db "nexttoc:";
        print $db $hotoc{$toc}{nexttoc}, "\n";
        $i++;
    }
    close($db);

    $i = 0;
    $file = "_debug_inpod.debug";
    open($db, ">", $file) or die "unable to open $file";
    foreach my $inpod ( @inpod ) {
        print $db $inpod, "\n";
    }
    close($db);

    return 0;
}

=begin wiki

!3 Function debug_prep

/Parameters/

None

/Description/

This function is used to dump the contents of @format to an individual file \
for inspection.

=cut

sub debug_prep {
    my $self = shift;
    my ($db, $i);

    $i = 0;
    my $file = "_debug_format.debug";
    open($db, ">", $file) or die "unable to open $file";
    foreach my $line ( @format ) {
        print $db $line, "\n";
    }
    close($db);

    $i = 0;
    $file = "_debug_nonformat.debug";
    open($db, ">", $file) or die "unable to open $file";
    foreach my $line ( @nonformat ) {
        print $db $line, "\n";
    }
    close($db);

    return 0;
}

=begin wiki

!3 Function debug_params

/Parameters/

None

/Description/

This function is used to dump the contents of the document info hash and \
the object parameters.

=cut

sub debug_params {
    my $self = shift;

    my $width = 0;
    foreach my $key ( @object_param_keys ) {
        if ( length($key) > $width ) { $width = length($key); }
    }

    foreach my $key ( sort @object_param_keys ) {
        printf("%-${width}s docinfo: ", $key);
        if ( defined $docinfo{$key} ) {
            print $docinfo{$key};
        } else {
            print "UNDEFINED";
        }
        print "\n";
        printf("%-${width}s object : ", '');
        if ( defined $self->{'_'.$key} ) {
            print $self->{'_'.$key};
        } else {
            print "UNDEFINED";
        }
        print "\n", '-'x(19), "\n";
    }

    return 0;
}

=begin wiki

!3 Function html_add_cell_spacing

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

/Test/

%insert name of test script here%

=cut

sub html_add_cell_spacing {
    my ($self, $html) = @_;

    $$html =~ s/<td>/<td>&nbsp;&nbsp;/gm;
    $$html =~ s/<\/td>/&nbsp;&nbsp;<\/td>/gm;

    return 0;
}

=begin wiki

!3 Function html_pad_empty_cells

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

/Test/

%insert name of test script here%

=cut

sub html_pad_empty_cells {
    my ($self, $html) = @_;

    $$html =~ s/&nbsp;&nbsp;\.&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;&nbsp;/gm;

    return 0;
}

=begin wiki

!3 Function html_insert_line_breaks

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

----

=cut

sub html_insert_line_breaks {
    my ($self, $html) = @_;

    $$html =~ s/##BR##/&nbsp;&nbsp;<br \/>&nbsp;&nbsp;/gm;

    return 0;
}

=begin wiki

!3 Function html_insert_line_breaks

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

----

=cut

sub html_insert_checkmarks {
    my ($self, $html) = @_;

    if ( $self->{_usesvg} eq "yes" ) {
        if ( $$html =~ /##CM##/ ) {
            $$html =~ s/##CM##/<object type=\"image\/svg+xml\" name=\"checkmark\" data=\"checkmark.svg\" width=\"18\" height=\"18\" border=\"0\"<\/object>/gm;
            $self->write_checkmark_svg;
        }
    } else {
        $$html =~ s/##CM##/<em>V<\/em>/gm;
    }

    return 0;
}

=begin wiki

!3 Function html_set_borders

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

If the borders macro is found in the first cell of a table, replace the table \
tag with a style callout that will style the table with the appropriately \
specified border.

If the %##NOBORDERS##% tag is found in the first table cell, replace the <table> \
tag with <table class="hidden">.

If the %##BORDERS##% tag is found in the first table cell, replace the <table> \
tag with <table class="solid">.

This references the "hidden" and "solid" classes defined for you in the \
embedded style sheet.

/Test/

%insert name of test script here%

----

=cut

sub html_set_borders {
    my ($self, $html) = @_;

    $$html =~ s/(<table>)(.*?<tr>.*?<td>)(.*?)(\#\#NOBORDERS\#\#)/<table class=\"hidden\">$2$3/gms;
    $$html =~ s/(<table>)(.*?<tr>.*?<td>)(.*?)(\#\#BORDERS\#\#)/<table class=\"solid\">$2$3/gms;

    return 0;
}

=begin wiki

!3 Function html_set_bgcolors

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

Provide support for table background colors. When ##BGRxxxxxx## is placed in \
a <tr> tag the table row color will be modified. When ##BGCxxxxxx## is placed \
in a <td> tag the table cell color will be modified. The string "xxxxxx" is a \
hex color code.

----

=cut

sub html_set_bgcolors {
    my ($self, $html) = @_;

    $$html =~ s/<tr>(.)<td>(&nbsp;&nbsp;)\#\#BGR([A-Fa-f0-9]{6,6})\#\#( ?)/<tr bgcolor=\"\#$3\">$1<td>$2/gms;
    $$html =~ s/<td>(&nbsp;&nbsp;)\#\#BGC([A-Fa-f0-9]{6,6})\#\#( ?)/<td bgcolor=\"\#$2\">$1/gms;

    return 0;
}

=begin wiki

!3 Function html_replace_nul

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

Replace <nul> tags with blank (nothing).

/Test/

%insert name of test script here%

=cut

sub html_replace_nul {
    my ($self, $html) = @_;

    $$html =~ s/<nul>//gm;

    return 0;
}

=begin wiki

!3 Function html_fixes

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

Perform misc fixes.

/Test/

%insert name of test script here%

=cut

sub html_fixes {
    my ($self, $html) = @_;

    ## modifier s treats the string as a single line so . will match newline
    $$html =~ s#</table>.<hr />#</table><br /></p><hr />#gs;

    return 0;
}

=begin wiki

!3 Function html_syntax_highlight

/Parameters/

* %$html% - reference to the html to be modified

/Description/

/Test/

%insert name of test script here%

=cut

sub html_syntax_highlight {
    my ($self, $html) = @_;

    $$html =~ s/^ <h1>/<h1>/g;  ## other clean-up... move?

    while ( $$html =~ /(^ % .*?^ %%)/gms ) {
        my $code = $1;

        $code =~ /^ % language=(\w+)/;
        my $language = $1;
        $language = "Perl" unless $language;
        ## herein lies a problem, this translates to 2 <BR>'s before getting to code
        $code =~ s/^ % language=(.*)//;  ## remove language
        $code =~ s/^ %%//ms;             ## clean up code block
        $code =~ s/^ % ?//gms;           ## clean up code block

        ## Tiki encodes special chars, decode before highlighting
        $code =~ s/&gt;/>/gms;
        $code =~ s/&lt;/</gms;
        $code =~ s/&#39;/'/gms;
        $code =~ s/&quote;/"/gms;
        $code =~ s/&amp;/&/gms;
        ## there are probably more...

        ## implement plain text language oursleves
        if ( $language eq 'PlainText' ) {
            $$html =~ s/^ % .*? %%/$code/ms;
            return 0;
        }
        ## this is a hack to remove extra space, needs fixing
        if ( ! $self->{_format} eq "html" ) { $code =~ s/\n//; }

        my $highlighted = $self->html_syntax_highlight_language( $code, $language );
        $$html =~ s/^ % .*? %%/$highlighted/ms;
    }

    $$html =~ s/<pre>//gms;    ## need to incorporate this into regex above
    $$html =~ s/<\/pre>//gms;  ## need to incorporate this into regex above

    return 0;
}

=begin wiki

!3 Function html_syntax_highlight_language

/Parameters/

* %$code% - code to be highlighted
* %$language% - language to use for highlighting

/Description/

Submit code blocks to Syntax::Highlight::Engine::Kate highlighter.

/Test/

%insert name of test script here%

=cut

sub html_syntax_highlight_language {
    my ($self, $code, $language) = @_;

    if ( $language =~ /INI FILES|INIFILE|INIFILES|INI_FILES/i ) {
        $language = "INI Files";
    }
    if ( $language =~ /SQL|SQLPLUS/i ) {
        $language = "SQL";
    }

    $code =~ s/<q>/"/gms;
    $code =~ s/<\/q>/"/gms;

    my $hl = new Syntax::Highlight::Engine::Kate(
        language => $language,
        substitutions => {
            "<"  => "&lt;",
            ">"  => "&gt;",
            "&"  => "&amp;",
            " "  => "&nbsp;",
            "\t" => "&nbsp;&nbsp;&nbsp;&nbsp;",
            "\n" => "<BR>\n",
        },
        ## since a style is applied, the "face" and "size" attributes can be removed...
        format_table => {
            Alert => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#0000ff\">", "</font>"],
            BaseN => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#007f00\">", "</font>"],
            BString => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#c9a7ff\">", "</font>"],
            Char => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#ff00ff\">", "</font>"],
            Comment => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#7f7f7f\"><i>", "</i></font>"],
            DataType => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#0000ff\">", "</font>"],
            DecVal => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#00007f\">", "</font>"],
            Error => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#ff0000\"><b><i>", "</i></b></font>"],
            Float => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#00007f\">", "</font>"],
            Function => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#007f00\">", "</font>"],
            IString => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#ff0000\">", "</font>"],
            Keyword => ["<b><font face=\"courier new,courier,monospace\" size=\"2\">", "</font></b>"],
            Normal => ["<font face=\"courier new,courier,monospace\" size=\"2\">", "</font>"],
            Operator => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#ffa500\">", "</font>"],
            Others => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#b03060\">", "</font>"],
            RegionMarker => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#96b9ff\"><i>", "</i></font>"],
            Reserved => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#9b30ff\"><b>", "</b></font>"],
            String => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#ff0000\">", "</font>"],
            Variable => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#0000ff\"><b>", "</b></font>"],
            Warning => ["<font face=\"courier new,courier,monospace\" size=\"2\" color=\"#0000ff\"><b><i>", "</b></i></font>"],
            ##Alert        => ["<font color=\"#0000ff\">", "</font>"],
            ##BaseN        => ["<font color=\"#007f00\">", "</font>"],
            ##BString      => ["<font color=\"#c9a7ff\">", "</font>"],
            ##Char         => ["<font color=\"#ff00ff\">", "</font>"],
            ##Comment      => ["<font color=\"#7f7f7f\"><i>", "</i></font>"],
            ##DataType     => ["<font color=\"#0000ff\">", "</font>"],
            ##DecVal       => ["<font color=\"#00007f\">", "</font>"],
            ##Error        => ["<font color=\"#ff0000\"><b><i>", "</i></b></font>"],
            ##Float        => ["<font color=\"#00007f\">", "</font>"],
            ##Function     => ["<font color=\"#007f00\">", "</font>"],
            ##IString      => ["<font color=\"#ff0000\">", "</font>"],
            ##Keyword      => ["<b>", "</b></font>"],
            ##Normal       => ["", ""],
            ##Operator     => ["<font color=\"#ffa500\">", "</font>"],
            ##Others       => ["<font color=\"#b03060\">", "</font>"],
            ##RegionMarker => ["<font color=\"#96b9ff\"><i>", "</i></font>"],
            ##Reserved     => ["<font color=\"#9b30ff\"><b>", "</b></font>"],
            ##String       => ["<font color=\"#ff0000\">", "</font>"],
            ##Variable     => ["<font color=\"#0000ff\"><b>", "</b></font>"],
            ##Warning      => ["<font color=\"#0000ff\"><b><i>", "</b></i></font>"],
        },
    );

    my $highlight = '';
    foreach my $line ( split "\n", $code ) {
        my $high = $hl->highlightText( ' '.$line."\n" );
        $highlight .= " " . $high;
    }
    if ( $self->{_format} eq "codehtml" ) {
        return "<div class=\"syntaxhi\">\n".$highlight."<br></div>";
    } else {
        ##return "<div class=\"syntaxhi\">\n".$highlight."<br></div>";
        return "<div class=\"syntaxhi\" style=\"background-color: #efefef; border-style: dashed; border-width: 1px\">\n".$highlight."<br></div>";
    }
}

=begin wiki

!3 Function html_codeblock_tags

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

Replace /begin code block/ and /end code block/ markup with blank space.

=cut

sub html_codeblock_tags {
    my ($self, $html) = @_;

    ## code begin/end labels inserted by default
    if ( $self->{_codelabels} eq "yes" ) { return 0; }

    $$html =~ s/begin code block/&nbsp;/gm;
    $$html =~ s/<p><em>end code block<\/em><\/p>/<br>/gm;

    return 0;
}

=begin wiki

!3 Function html_add_header

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

=cut

sub html_add_header {
    my ($self, $html) = @_;

    my $header;

    $header = <<'    HEADER';
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
        <html>
        <head>
        <meta name="author" content="$author">
        <meta name="revised" content="$sysdate">
        <meta name="generator" content="WikiPod $VERSION">
        <title>$title</title>
        <style type="text/css">
          a:link {
            color: blue
          }
          a:visited {
            color: blue
          }
          table
          {
            border-collapse: collapse;
            border: 1px $bordertype;
            empty-cells: show
          }
          th
          {
            border-right: 1px $bordertype;
            border-left: 1px $bordertype;
            border-top: 1px $bordertype;
            border-bottom: 1px $bordertype;
            padding: 0.25em;
          }
          td
          {
            border-right: 1px $bordertype;
            border-left: 1px $bordertype;
            border-top: 1px $bordertype;
            border-bottom: 1px $bordertype;
            padding: 0.25em;
          }
          table.hidden
          {
            border-collapse: collapse;
            border: 1px hidden;
          }
          table.hidden th
          {
            border-collapse: collapse;
            border-style: hidden hidden hidden hidden;
          }
          table.hidden td
          {
            border-collapse: collapse;
            border-style: hidden hidden hidden hidden;
          }
          table.solid
          {
            border-collapse: collapse;
            border: 1px solid;
          }
          table.solid th
          {
            border-collapse: collapse;
            border-style: solid solid solid solid;
          }
          table.solid td
          {
            border-collapse: collapse;
            border-style: solid solid solid solid;
          }
          div#syntaxhi
          {
            background-color: #efefef;
            border-style: dashed;
            border-width: 1px
          }
        </style>
        </head>
        <body style="background-color: white">
        $linkback
    HEADER
    $header =~ s/^ {8,8}//gm;

    $header =~ s/\$title/$docinfo{title}/;
    $header =~ s/\$author/$docinfo{author}/;
    $header =~ s/\$bordertype/$self->{_bordertype}/gm;
    $header =~ s/\$linkback/$docinfo{linkback}/;
    $header =~ s/\$VERSION/$VERSION/;
    $header =~ s/\$sysdate/$sysdate/;

    $$html = $header . $$html;

    return 0;
}

=begin wiki

!3 Function html_add_footer

/Parameters/

* %$self% - reference to our object
* %$html% - reference to the html to be modified

/Description/

/Test/

%insert name of test script here%

=cut

sub html_add_footer {
    my ($self, $html) = @_;

    my $footer;
    $footer = <<'    FOOTER';
        </body>
        </html>
    FOOTER
    $footer =~ s/^ {8,8}//gm;

    $$html .= $footer;

    return 0;
}

=begin wiki

!3 Function text_wrap

/Parameters/

/Description/

/Test/

%insert name of test script here%

=cut

sub text_wrap {
    my ($self, $lines) = @_;

    my @temp = @{$lines};
    @{$lines} = ();

    my $len = $self->{_wrapcol};
    $Text::Wrap::columns = $self->{_wrapcol};
    my @wrapin;

    foreach my $line ( @temp ) {
        $line =~ s/^!(\d){1,1} //;  ## remove heading markup
        if ( $line =~ /^ % language/ ) { next; }  ## skip over start code
        if ( $line =~ /^ %%/ ) { next; }  ## skip over end code
        $line =~ s/^ % ?/  /;  ## skip over end code
        $line =~ s/\#\#BORDERS\#\#//g;  ## remove
        $line =~ s/\#\#NOBORDERS\#\#//g;  ## remove

        if ( length($line) > $len ) {
            $wrapin[0] = $line;
            my $wrapped = wrap('', '', @wrapin);
            push @{$lines}, $wrapped;
        } else {
            push @{$lines}, $line;
        }
    }

    return 0;
}

=begin wiki

!3 Function header_vars

/Parameters/

None

/Description/

Perform variable substitution in the header and footer strings using the \
%docinfo hash as the source for variable values.

/Test/

%insert name of test script here%

=cut

sub header_vars {
    my $self = shift;

    my $header = $self->{_header};
    chomp $header;
    $header .= ' ';
    while ( $header =~ /\$(\w+) / ) {
        my $var = $1;
        $header =~ s/\$$var/$docinfo{$var}/;
    }
    chomp $header;
    $self->{_header} = $header;

    return 0;
}

=begin wiki

!3 Function footer_vars

/Parameters/

None

/Description/

Perform variable substitution in the header and footer strings using the \
%docinfo hash as the source for variable values.

=cut

sub footer_vars {
    my $self = shift;

    my $footer = $self->{_footer};
    chomp $footer;
    $footer .= ' ';
    while ( $footer =~ /\$(\w+) / ) {
        my $var = $1;
        $footer =~ s/\$$var/$docinfo{$var}/;
    }
    chomp $footer;
    $self->{_footer} = $footer;

    return 0;
}

=begin wiki

!3 write_checkmark_svg {

/Parameters/

* %$self% - reference to ourself

/Description/

Subroutine to write the checkmark svg file to the output directory where the \
page html is written. CAUTION: Using this feature causes to an svg image file \
to be created wherever an html page is created. An enhancement to this feature \
would be to allow the user to specify a url for the checkmark file.

=cut

sub write_checkmark_svg {
    my ($self) = @_;

    my $svgimage = <<'    ENDSVG';
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!-- Created with Inkscape (http://www.inkscape.org/) -->
    <svg
       xmlns:dc="http://purl.org/dc/elements/1.1/"
       xmlns:cc="http://web.resource.org/cc/"
       xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:svg="http://www.w3.org/2000/svg"
       xmlns="http://www.w3.org/2000/svg"
       xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
       xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
       width="19.21315"
       height="18.294994"
       id="svg2"
       sodipodi:version="0.32"
       inkscape:version="0.45"
       sodipodi:modified="true"
       version="1.0">
      <defs
         id="defs4" />
      <sodipodi:namedview
         id="base"
         pagecolor="#ffffff"
         bordercolor="#666666"
         borderopacity="1.0"
         gridtolerance="10000"
         guidetolerance="10"
         objecttolerance="10"
         inkscape:pageopacity="0.0"
         inkscape:pageshadow="2"
         inkscape:zoom="7.9195959"
         inkscape:cx="17.757032"
         inkscape:cy="7.298821"
         inkscape:document-units="px"
         inkscape:current-layer="layer1"
         inkscape:window-width="984"
         inkscape:window-height="852"
         inkscape:window-x="148"
         inkscape:window-y="66" />
      <metadata
         id="metadata7">
        <rdf:RDF>
          <cc:Work
             rdf:about="">
            <dc:format>image/svg+xml</dc:format>
            <dc:type
               rdf:resource="http://purl.org/dc/dcmitype/StillImage" />

          </cc:Work>
        </rdf:RDF>
      </metadata>
      <g
         inkscape:label="Layer 1"
         inkscape:groupmode="layer"
         id="layer1"
         transform="translate(-192.905,-516.02064)">
        <path
           style="fill:#000000"
           d="M 197.67968,534.31563 C 197.40468,534.31208 196.21788,532.53719 195.04234,530.37143 L 192.905,526.43368 L 193.45901,525.87968 C 193.76371,525.57497 194.58269,525.32567 195.27896,525.32567 L 196.5449,525.32567 L 197.18129,527.33076 L 197.81768,529.33584 L 202.88215,523.79451 C 205.66761,520.74678 208.88522,517.75085 210.03239,517.13691 L 212.11815,516.02064 L 207.90871,520.80282 C 205.59351,523.43302 202.45735,527.55085 200.93947,529.95355 C 199.42159,532.35625 197.95468,534.31919 197.67968,534.31563 z "
           id="path2223" />
      </g>
    </svg>
    ENDSVG
    $svgimage =~ s/^ {4,4}//gm;

    my ($volume,$outpath,$file) = File::Spec->splitpath( $self->{_outfile} );
    my $svgfile = $outpath . 'checkmark.svg';
    open(my $fh, ">", $svgfile) or die "unable to create svg file";
    print $fh $svgimage;
    close $fh;

    return 0;
}

=begin wiki

!1 BUGS

Please advise me of any bugs that you may encounter. Bugs will be corrected as \
quickly as possible.

----

!1 TO DO

I am considering adding support for other wiki markup engines besides \
Text::Tiki, but this will probably be request driven.

----

!1 COPYRIGHT

All rights reserved. This software is distributed under the same terms as Perl \
itself.

----

!1 AUTHOR

Brad Adkins, dbijcl at gmail dotcom

----

!1 REFERENCES

The base markup provided by Text::Tiki module. Please see the POD in the \
Text::Tiki module for additional information about Wiki markup in general, and \
Text::Tiki markup in particular.

----

=cut

1;
