#!/usr/bin/perl -w
# $Id: setext2html.txt,v 1.9 2007/09/08 $
# setext -> HTML converter
#
# (C) 2002 Erik Oliver
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.


use strict;
use Carp;

# Global variables
my $numargs = @ARGV;
my $infile;
my $outfile;
my %href;
my @toc;
my $tocindex = -1;

sub style_encode($) {
       use HTML::Entities;
       my $string = shift;
       my $flag = 0;

       $string = encode_entities($string,"<>&");

       # debugging: print the ho-tt matching lines
#       if ($string =~ m#\b(\S+)_\b#) {
#               print STDERR "IN:  ", $string, "\n";
#               $flag = 1;
#       }

       # bold-tt
       $string =~ s#\*\*([^\*]*)\*\*#<strong>$1</strong>#g;

       # italic-tt
       $string =~ s#~(\S*)~#
               ($a = $1) =~ s,~, ,g; "<em>$a</em>"#eg;

       # underline-tt
       $string =~ s#\b_(\S*)_\b#
               ($a = $1) =~ s,_, ,g; "<em>$a</em>"; #eg;

       # hot-tt
       my $h;
       $string =~ s#\b(\S+)_\b#
                       $h = $href{$1};
                       ($a = $1) =~ s,_, ,g;
                       $h ? qq'<a href="$h">$a</a>' : qq'$a'; #eg;

#       if ($flag == 1) {
#               print STDERR "OUT: ", $string, "\n";
#       }

       return($string);
}

sub encode_only($) {
       use HTML::Entities;
       my $string = shift;

       $string = encode_entities($string,"<>&");

       return($string);
}

if ($numargs == 1) {
       if($ARGV[0] =~ s/\.etx$// ) {
               print STDERR "warning: one argument form used but called with $ARGV[0].etx, argument shortened to $ARGV[0].\n";
       }

       $infile = "$ARGV[0].etx";
       $outfile = "$ARGV[0].html";
} elsif ($numargs == 2) {
       $infile = $ARGV[0];
       $outfile = $ARGV[1];
} else {
       print STDERR "usage: $0 infile.etx outfile.html\n";
       print STDERR "usage: $0 inoutfile\n";
       exit -1;
}

if (! -e $infile) {
       print STDERR "error: Input, $infile, does not exist\n";
       exit -1;
}

if (! -r $infile) {
       print STDERR "error: Input, $infile, not readable\n";
       exit -1;
}

open INFILE, "<$infile" ||
       die "Could not open $infile for reading, $!";
my @data = <INFILE>;    # slurp input
chomp @data;            # strip newlines
close INFILE;

open OUTFILE,">$outfile" ||
       die "Could not open $outfile for writing, $!";

## Loop 1: Find any href-tt tags and hash the URL against a key
## [Also escape a literal "`" with +++.
for(my $loop=0; $loop <= @data; $loop++)
{
       if(!$data[$loop]) { next; } # skip blank lines

       # href-tt finder: .. _href URL
       if($data[$loop] =~ /^\.\.\s+_(\S*)\s+(.*)\s*/ ) {
               my $key = $1;
               my $pos = $loop + 1;
               my $value = $2;
               $data[$loop] = "";
               while ($pos <= $#data) {
                       # lookahead
                       if($data[$pos] =~ m/^\.\. ([^_])/) {
                               $value .= "$1";
                               $data[$pos] = "";
                               $pos++;
                               next;
                       } else {
                               last;
                       }
               }
               $href{$key} = encode_entities($value,"<>&");
       }
       $data[$loop] =~ s/``/+++/g;
}

my ($htmltitle, $htmlauthor, $htmldate) = ("","","");

## Loop 2: Find headers and flow paragraphs, etc. together
for(my $loop = 0; $loop <= @data; $loop++)
{
       if(!$data[$loop]) {next;} # skip blank lines
       $_ = $data[$loop];

       if(/^\.\. / ) {
               # supress-tt
               $data[$loop] = "";
       } elsif (/^Subject: (.*$)/) {
               if($htmltitle eq "") {
                       $htmltitle = style_encode($1);
               }
               $data[$loop] = "";
       } elsif (/^From: (.*$)/) {
               if($htmlauthor eq "") {
                       $htmlauthor = $1;
               }
               $data[$loop] = "";
       } elsif (/^Date: (.*$)/) {
               if($htmldate eq "") {
                       $htmldate = $1;
               }
               $data[$loop] = "";
       } elsif (/^===/) {
               if($htmltitle eq "") {
                       $htmltitle = style_encode($data[$loop-1]);
               }
               $tocindex++;
               my $headline = style_encode($data[$loop-1]);
               my $id = "sh$tocindex";
               $toc[$tocindex] = "1:$headline";


               $data[$loop-1] = "<h1 id=\"$id\">$headline</h1>\n";
               $data[$loop] = "";
       } elsif (/^---/) {
               if($htmltitle eq "") {
                       $htmltitle = style_encode($data[$loop-1]);
               }
               $tocindex++;
               my $headline = style_encode($data[$loop-1]);
               my $id = "sh$tocindex";
               $toc[$tocindex] = "2:$headline";

               $data[$loop-1] = "<h2 id=\"$id\">$headline</h2>\n";
               $data[$loop] = "";
       } elsif (/^\s{0,2}\* /) {
               # this is a list
               $data[$loop] =~ s/^\s*\* //;
               $data[$loop] = "<ul><li>" . style_encode($data[$loop]);
               my $pos = $loop+1;
               while($pos <= $#data) {
                       if($data[$pos] =~ s/^\s{0,2}\* //) {
                               $data[$loop] .= "</li>\n<li>" . style_encode($data[$pos]);
                               $data[$pos] = "";
                               $pos++;
                       } elsif ($data[$pos] =~ s/^  ([^ *])/$1/) {
                               $data[$loop] .= " " . style_encode($data[$pos]);
                               $data[$pos] = "";
                               $pos++;
                       } else {
                               last;
                       }
               }
               $data[$loop] .= "</li></ul>\n";
       } elsif (/^\s{0,2}>\s*/) {
               # this is included text with a ">"
               $data[$loop] =~ s/^\s{0,2}>\s*//;
               $data[$loop] = style_encode($data[$loop]);
               my $pos = $loop+1;
               while($pos <= $#data) {
                       if($data[$pos] =~ s/^\s{0,2}>\s*//) {
                               if($data[$pos] eq "") {
                                       $data[$loop] .= " <br />";
                               } else {
                                       $data[$loop] .= " ". style_encode($data[$pos]);
                                       $data[$pos] = "";
                                       $pos++;
                               }
                       } else {
                               last;
                       }
               }

               $data[$loop] = "<blockquote>" . $data[$loop] . "</blockquote>\n";
       } elsif (/^  [^ ]/) {
               # this is body text to wrap up
               $data[$loop] =~ s/^  //;
               $data[$loop] = style_encode($data[$loop]);
               my $pos = $loop+1;
               while($pos <= $#data) {
                       if($data[$pos] =~ s/^  ([^ >])/$1/) {
                               $data[$loop] .= " " . style_encode($data[$pos]);
                               $data[$pos] ="";
                               $pos++;
                       } else {
                               last;
                       }
               }
               $data[$loop] = "<p>" . $data[$loop] . "</p>\n";
       } elsif (/`/) {
               # if nothing else and there is a ` assume multiline
               # verbatim environment
               $data[$loop] =~ s/`//;
               $data[$loop] = encode_only($data[$loop]);
               my $pos = $loop+1;
               while($pos<= $#data) {
                       if($data[$pos] =~ s/`//) {
                               if($data[$pos] ne '') {
                                       $data[$loop] .= "\n". encode_only($data[$pos]);
                                       $data[$pos] = "";
                               }
                               last;
                       } else {
                               $data[$loop] .= "\n" . encode_only($data[$pos]);
                               $data[$pos] = "";
                               $pos++;
                       }
               }
               $data[$loop] = "<pre>" . $data[$loop] . "</pre>\n";
       } elsif (/\$\$/) {
               $data[$loop] = "<span class=\"twobuck-tt\">" . $data[$loop] . "</span>";
       } elsif (/^\s*$/) {
               $data[$loop] = ""; # effectively a blank line
       } else {
               # should only be here if at end or next line is the === or ---
               next if ($loop == $#data);
               next if ($data[$loop+1] =~ /^===/);
               next if ($data[$loop+1] =~ /^---/);

               carp "Unhandled typotag, line = $loop, \"$_\"\n";
       }
}

print OUTFILE qq|
<html>
<head><title>$htmltitle</title>
<style type="text/css">
body { margin: 0; padding: 0; font-family: Verdana, sans-serif; color: #000; background: #ffd; }
content { padding: 10px 20px; margin: 5% 10%; border: 1px dotted #333; background: #fff; }
twobuck-tt {color: #040; }
p { margin-top: 0; padding-top: 0; line-height: 1.5em, margin-bottom: 1em; }
h1 {font-size: 2em; }
h2 {font-size: 1.75em; }
h1, h2 { margin: 1.25em 0 0 0; font-family: Verdana, sans-serif; }
pre { font: Courier, "Courier New", monospace; }
a { text-decoration:none; font-weight:600; }
a:hover {background-color:#eee;}

</style>
</head>
<body>
<div class="content">
|;

# header information
print OUTFILE "<h1>$htmltitle</h1>\n" if ($htmltitle);
print OUTFILE "<p>By ",encode_only($htmlauthor),"</p>\n" if ($htmlauthor);
print OUTFILE "<p>$htmldate</p>\n" if ($htmldate);

# table of contents?
print OUTFILE "<h1>Table of Contents</h1>\n";
print OUTFILE "<ul>\n";
my $lastlevel = 0;
for(my $loop = 0; $loop <= $tocindex; $loop++)
{
       $_ = $toc[$loop];
       m#([^:]*):(.*)#;
       my $level = $1;
       my $content = $2;

       next if $level == 2;

       if($lastlevel == 0) {
               # first entry
               print OUTFILE qq|<li><a href="#sh$loop">$content</a>|;
               $lastlevel = $level;
       } elsif ($lastlevel == $level) {
               # stayed same, end prior entry start new one
               print OUTFILE qq|</li>\n<li><a href="#sh$loop">$content</a>|;
       } elsif ($level == 2 && $lastlevel == 1) {
               # starting new level
               print OUTFILE qq|\n<ul>\n<li><a href="#sh$loop">$content</a>|;
               $lastlevel = $level;
       } elsif ($level == 1 && $lastlevel == 2) {
               # finishing a level
               print OUTFILE qq|</li>\n</ul>\n</li>\n<li><a href="#sh$loop">$content</a>|;
               $lastlevel = $level;
       } else {
               print STDERR "toc error lastlevel vs level mismatch\n";
               die;
       }
}
print OUTFILE "</li></ul>\n";
if ($lastlevel == 2) { print OUTFILE "</li></ul>\n"; }

for(my $loop = 0; $loop <= @data; $loop++)
{
       if(!$data[$loop]) {next;} # skip blank lines
       $data[$loop] =~ s/\+\+\+/`/g;
       print OUTFILE "$data[$loop]\n";
}

print OUTFILE qq|
</div>
</body></html>
|;

close OUTFILE;