package Pod::WikiText;

=head1 NAME

WikiText - Support for the use of Wiki markup.

=head1 SUMMARY

Support the use of Wiki markup for general documentation purposes. This
module uses the Text-Tiki module for markup support. The purpose of this
module is to provide a convenient way to incorporate Wiki markup into
lots of different types of documents including, but not limited to, your
own Perl source files.

=head1 SYNOPSIS

    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.

=head1 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.

=head1 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.

Caveat: You should probably not use WikiText as POD in source files that you
plan to upload to CPAN, unless you include normal POD as well. :-)

=head1 ADDITIONAL INFORMATION

Please see the WikiText documentation embedded in this source file for additional
details on how to use WikiText.pm. You can view this documentation using
WikiText.pm itself to format the WikiText content in this file. Hint: download and
install WikiText.pm.

Thank you!

=head1 COPYRIGHT

Copyright 2008 Brad Adkins <dbijcl@gmail.com>.

Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no
Back-Cover Texts.

=head1 AUTHOR

Brad Adkins, dbijcl@gmail.com

=cut

=begin wiki

!1 NAME

Pod::WikiText.pm

Support for Wiki markup in POD.

----

!1 SYNOPSIS

 % language=Perl
 % use Pod::WikiText;
 %
 % my $formatter = Pod::WikiText->new(
 %     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.

----

!1 Development Notes

The following notes are largely intended for the developer (me), but you may
find them informative.

!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 To Do - 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

Tests beyond the basic "can load" need to be written.

!2 Future Enhancements

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

----

=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.08";
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

Copyright 2008 Brad Adkins <dbijcl@gmail.com>.

Permission is granted to copy, distribute and/or modify this document under the \
terms of the GNU Free Documentation License, published by the Free Software \
Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no \
Back-Cover Texts.

----

!1 AUTHOR

Brad Adkins, dbijcl@gmail.com

----

!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;

__END__
