#!/usr/bin/perl -w
# 
# thm2htm,  Harry Plantinga.  This program may be copied
# under the terms of the Artistic License.
#
# convert ThML files to HTML webs.  This version doesn't
# parse and is loose about accepting invalid ThML files.
#
# v1.0 -- now it's all in one big file.  Usage:
# thm2htm  [options] bookID.thm
#
use strict;
use Getopt::Long;

my ($bookID,$author,$authorID,$auth,$publisherID,$version,$title,$input);
my ($head,$body,$prev,$filename,$this,$notenum,$footnotes,$rights,$status);
my ($DCpublisher,$DCdate,$DCtype,$DCsource,$DClanguage,$DCformat);
my ($published,$series,$URL,$ISBN,$description,$meta);
my ($digitized, $typed, $thml, $display, %idfile, %ids_used, $id);
my ($OPF, $manifest, $spine, $guide, $fileas);
my ($refcount, $versionDefault, $bookDefault);
my $unknowns = 0;
my $divid = "1";

my ($debug, $MinDivSizeDefault, $ccelhacks, $onefile, $png);
GetOptions('debug' => \$debug,			# turn on debugging
           'ccel' => \$ccelhacks,		# turn on ccel hacks
	   'png' => \$png,			# link static png images
           'onefile' => \$onefile,		# make one HTML file
	   'size=i' => \$MinDivSizeDefault);	# set min div size default

$MinDivSizeDefault ||= 3000; # -snnnn to set mindivsize
$debug ||= 0;
$ccelhacks ||= 0;
$png ||= 0;
$onefile ||= 0;

# read bible book name abbreviations;
my (@bookName, @chapters, %bookID, @bookaliases, @volumes, %entfile);
&readbookID;				
dbmopen %idfile, "htm/idfile", 0666 or warn "Can't open idfile dbm file-$!\n";

mkdir ("htm",0777) unless -e "htm";     #make directory for html files
#`rm -f htm/*.htm`;			#delete old html files

my $ssprefix = &findStylesheets();
print "Found ss and pix htm/$ssprefix\n";

while (<>) 				#read entire file into $input
  { $input .= $_; }
$_ = $input;
die "Uuurrgh! empty input file\n" unless $input;
print "\nthm2htm: " . length($input) . " bytes read\n";

&getInfo($input);		        # get author, title, etc out of header

$input =~ s|<deleted.*?</deleted>||gsi;	#delete deleted stuff

$input = &normalizeDivs($input); 	# fix up </divn> tags (add omitted endtags)
$input = &identify($input);		# add ids if they ain't already there
$input = &parsescr($input);		# parse scripture references
$input = &index($input);		# build indexes



# separate out head and body
$input =~ m|^(.*)</ThML.head>.*?<ThML.body[^>]*>(.*?)</ThML.body>|si;
$head = $1; $body = $2;
die "Ill-formed ThML document\n" unless $head and $body;

die "Hey -- there's no <div1> element.\n" . 
    "You should be using thm2htm-nodiv instead.\n" if ($body !~ m|<div1|);
my $twodivs = $body =~ m/<div\d.*<div\d/is;
$onefile = 1 if !$twodivs;

&processHead($head,$twodivs);	#process ThML.head -- make info page
&processBody($body);		#process ThML.body -- make web

my $relurl = "htm/TOC.htm";
$relurl = "htm/i.htm" if -f "htm/i.htm";
$relurl = "htm/$bookID.htm" if $onefile;
$authorID =~ m/^(.)/;
my $url = "/$1/$authorID/$series$bookID/$relurl";
print "HTML starts at $url\n";

print "$unknowns id mappings were unresolved: " .
        "it might help to re-run this program.\n" if $unknowns;

exit(0);


#-------------------------subroutines----------------------------
#
# sub findStylesheets -- look for needed stylesheets in the 
# directory ../../../ss.  If not found, create them in htm/ss.
#
sub findStylesheets {

my $sspath = "..";
if (-f "../../../ss/ThML10.css") {
    $sspath = "../../..";
  } elsif (-f "ss/ThML10.css") {
    $sspath = "..";
  } else {
    warn "Couldn't find stylesheets -- place them in the current directory or
    at ../../../ss so they can be shared among books.  Thanks! --the management";
  }
return $sspath;
}



#
# This subroutine converts ccel-style URIs to URLs that will work
# with the multiple htm files generated by this program.
#
# ccel-style URI: /ccel/authorID/bookID.htm|hash
#                 /ccel/authorID/seriesID/bookID.htm|hash
#
# The URIs that are not to this authorID/bookID are left as is.
# They can be interpreted on the fly by the CCEL server (or perhaps 
# converted by another program reading the idfile dbm to get the 
# filename).
#
sub uri2url
{
  my $uri = shift;
  my $uri_old = $uri;
# print "uri2url got $uri";
  my ($url, $vol,%volidfile,$file);
  $url = $uri;

  # is this a CCEL-style URI link within this book?
  if ($uri =~ s!^(/ccel/$authorID/$bookID.htm)?\|!!i) {	 
    $file = $idfile{$uri};
    if ($file) {
      $url = "$file#$uri";
    } else {
      $url = $uri_old;
      $unknowns++;
      print "  Couldn't find ID $uri\n";
    }
 
  # is this a CCEL-style URI link to a volume of this series?
  } elsif ($uri =~ s!^/ccel/$authorID/$bookID/(.*?).htm\|!!) { 
    $vol=$1;
    $file = $volidfile{$uri};
    if ($file) {
      $url = "../$vol/htm/$file#$uri";
    } else {
      $url = $uri_old;
      $unknowns++;
      print " Couldn't find ID $uri in volume $vol\n";
    }
  }
# print " returning $url\n";
  return "href=\"$url\"";
}


# get some important info from the header: 
# title, author, bookID, authorID, etc.
#
sub getInfo
{
  $_ = shift;
  m|<DC.Title.*?>(.*?)</DC.Title\s*>|is; $title = $1 || "";
  m|<DC.Creator.*?>(.*?)</DC.Creator\s*>|is; $author = $1 || "";
  m|<DC.Creator.*?scheme="file-as">(.*?)</DC.Creator\s*>|is; $fileas = $1||"";
  $auth = "";
  $auth = "<h3 class=\"subhead\">by</h3>\n" .
          "<h2 class=\"subhead\">$author</h2>" 
	    unless $author =~ m/anonymous/i;
  m|<DC.Rights.*?>(.*?)</DC.Rights\s*>|is; $rights = $1 || "";
  m|<DC.Publisher.*?>(.*?)</DC.Publisher\s*>|is; $DCpublisher = $1 || "";
  m|<DC.Date.*?>(.*?)</DC.Date\s*>|is; $DCdate = $1 || "";
  m|<DC.Type.*?>(.*?)</DC.Type\s*>|is; $DCtype = $1 || "";
  m|<DC.Format.*?>(.*?)</DC.Format\s*>|is; $DCformat = $1 || "";
  m|<DC.Source.*?>(.*?)</DC.Source\s*>|is; $DCsource = $1 || "";
  m|<DC.Language.*?>(.*?)</DC.Language\s*>|is; $DClanguage = $1 || "";
  m|<DC.Identifier.*?>(http.*?)</DC.Identifier\s*>|is; $URL = $1 || "";
  m|<DC.Identifier[^>]*scheme="ISBN"[^>]*>(.*?)</DC.Identifier\s*>|is; 
    $ISBN = $1 || "";
  $bookID=$1        if m|<bookID\s*>(.*?)</bookID\s*>|is; 
  $authorID=$1      if m|<authorID\s*>(.*?)</authorID\s*>|is; 
  $publisherID=$1   if m|<publisherID\s*>(.*?)</publisherID\s*>|is; 
  $published=$1     if m|<published\s*>(.*?)</published>|is;
  $version=$1       if m|<version\s*>(.*?)</version\s*>|is; 
  $series=$1        if m|<series\s*>(.*?)</series\s*>|is; 
  $series ||= "";
  $series = "" if $series eq $bookID;
  $series .= "/" if $series;
  $status=$1        if m|<status\s*>(.*?)</status\s*>|is; 
  $description=$1   if m|<description\s*>(.*?)</description\s*>|is;
  $description||=$1 if m|<DC.description\s*>(.*?)</DC.description\s*>|is;
  $description||="";
  print "Making HTML version of $title by $author\n";
}
  

#
#  Make an info page out of the ThML.head information
#
sub processHead
{
  $_ = shift;
# print "In processingHead\n";
  my $linkTOC = shift;

#
#output the stylesheet which is common for all sections of this doc
#
  my $name=">htm/styles.css";
  open STYLES, $name or die $!;
  my $styles="";
  $styles = $1 if s|<style.*?>(.*?)</style\s*>||is;
  s|<link.*/?>||gis;
  $styles = "span.avoidemptystylesheets: {}\n" unless $styles;
  print STYLES $styles;
  close STYLES;


#
# create the index.htm file, which has info about the book.
# It should have meta tags, doc info, links to other formats.
#
my $rpath = "/$authorID/$series$bookID/htm";

my $toclink = "
<h3 class=\"subhead\"><a class=\"TOC\" href=\"htm/TOC.htm\">Table 
  of Contents</a></h3>";

open INFO, ">index.htm" or die $!;

$description = "<p>$description</p>\n" if $description;
my $infosect = "
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"
    \"http://www.w3c.org/TR/REC-html40/loose.dtd\">
<html><head>
<title>$title</title>
<link rel=\"stylesheet\" type=\"text/css\" href=\"htm/$ssprefix/ss/ThML10.css\">
<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">
==metadata==
</head><body>
<h1 class=\"title\">$title</h1>
$auth
<h3 class=\"subhead\"><i>CCEL Edition v$version</i></h3>
<p>&nbsp;</p>
$description
<p>&nbsp;</p>
<hr>
$toclink
<hr>
";

  s|<(.*?)></\1\s*>\s*||gm;  #delete empty <x></x> tags
  retag("!DOCTYPE",	"_detag");
  retag("ThML",	"_detag");
  retag("ThML.head",	"_detag");
  retag("meta",	"_detag");

  #
  # process each of generalInfo, printSourceInfo, elecEdInfo separately
  #
  s@<(generalInfo|printSourceInfo|electronicEdInfo)\s*>(.*?)</\1\s*>@headsect($1,$2)@egs;

  $infosect =~ s/==metadata==/$meta/;
  print INFO $infosect . $_ . "</body></html>\n";
  close INFO;
}


# 
#  Put the Table of Contents and each <divn>...</divn> into a 
#  separate file.
#
sub processBody
{
  my $bod = shift;
# print "In processBody\n";
  $filename = "TOC.htm";
  $prev = "TOC.htm";
  
  my $toc = head("$title - TOC");
  $toc .= 
  	 "<h1 class=\"title\">$title</h1>\n" .
	 $auth .
  	 "<hr><h1 class=\"title\">Table of Contents</h1>\n" .
  	 "<p class=\"TOC1\"><a class=\"TOC\" href=\"../index.htm\">" .
       	 "<i>About This Book</i></a></p>\n";
  
  #
  # For each divn tag we add a TOC entry, then put the contents
  # into a separate file.
  #
  my ($oldlevel, $level, $rest, $content, $r, $n, $shortdiv, $add_to_div);
  my ($divID, $divtitle, $nextID, $nexttitle, $next, $fname);
  my ($levelup, $leveldown, $nextlevel);

  $level="0";
  while ($bod =~ m|<div[1-7]|)		# while there is a remaining <div
  {
    $oldlevel = $level;
    if ($bod =~ m|<div[1-7].*?<div[1-7]|s) 	#if there are two divns left
    { 
      $bod =~ s|.*?<div([1-7])(.*?)>(.*?)(<div[1-7])|$4|s; 
      $level = $1;
      $rest = $2;
      $content = "<div $2>$3</div>\n";
      $content =~ s|</div\d>\s*||gs;
    } 
    else
    { 
      $bod =~ s|.*?<div([1-7])(.*?)>(.*)||s; 
      $level = $1;
      $rest = $2;
      $content = "<div $2>$3</div>\n";
      $content =~ s|</div\d>\s*||gs;
    }
#   print "  found <div$level $rest>\n";

    my $fileBreakSize = $MinDivSizeDefault;
    $fileBreakSize = $1 if $rest =~ m/filebreak="([^"]*)"/i;

    $content = $add_to_div . $content if $add_to_div;
    $shortdiv = (length($content) < $fileBreakSize);
    $n = "" if $level ne $oldlevel;
    $levelup   = ($level < $oldlevel); 
    $leveldown = ($level > $oldlevel); 

    ($divID, $divtitle, $fname) = getName($rest);
    if (!$add_to_div) {		# if not merging this div with the last
        $prev = $this;		# remember last division
        $filename = $fname;
    }
    $this = "$filename#$divID";

    $next = "TOC.htm";
    if ($bod =~ m|.*?<div([1-7])(.*?)>|s)
    { 
      $nextlevel = $1;
      ($nextID, $nexttitle, $next) = getName($2);
    }

    # print div tags needed for collapsable outline
    if ($leveldown && $oldlevel ne "0") {
	$display = "block";
	$display = "none" if $level > 2;
        $toc .= "<div id=\"d$divid\" style=\"display:$display\">\n";
	$divid++;
    }
    if ($levelup) {
        my $ol = $oldlevel;
	while ($level < $ol) {
	    $toc .= "</div>\n";
	    $ol--
	}
    }

    $toc .= "<p class=\"TOC$level\"><a class=\"TOC\" href=\"$this\">";
    $toc .= "$divtitle</a></p>\n";

    if ($onefile or ($shortdiv and $level<=$nextlevel and $nextlevel>1)) {
                                               # if division is too short and 
        $add_to_div = $content;		       # next div is not lower level
        $add_to_div = "  " unless $add_to_div; # and next div is not level 1
	$idfile{$divID} = $filename;	       # just remember this division
    } else {				       # else write out file
        $add_to_div = "";
        open OF, ">htm/$filename" or die $!;
        print OF processDiv($content,$divID,$divtitle,$prev,$next,$filename);
        close OF;
        $manifest .= "\n <item id=\"$divID\" href=\"htm/$filename\""
                  .  " media-type=\"text/x-oeb1-document\"/>";
    }
    $spine .= "\n <itemref idref=\"$divID\"/>"
  }
  if ($add_to_div) {		#stuff left over -- process it
    open OF, ">htm/$filename" or die $!;
    print OF processDiv($content, $divID, $divtitle, $prev, $next,$filename);
    close OF;
  }
  
  $toc .= "\n<hr><p style=\"font-size:small\"><a href=";
  $toc .= "\"/info/nav.htm\">Navigation and searching hints</a>\n";
  $toc .= "</body></html>\n";

  # now add expandability to the TOC
  $toc =~ s|(<p class="TOC[^>]*>)(<a class="TOC[^>]*>[^<]*</a></p>\s*<div id="d([^"]*)" style="display:([^"]*)")|$1<a href="javascript:t(d$3,p$3)"><img border=0 src="$ssprefix/pix/$4.gif" id="p$3"></a> $2|gsi;
  $toc =~ s/block.gif/open.gif/g;
  $toc =~ s/none.gif/shut.gif/g;

  open TOC, ">htm/TOC.htm" or die $!;
  print TOC $toc;
  close TOC;

}


#
# handle one divn of the document
#
sub processDiv
{
  my ($div, $divID, $divtitle, $prev, $next, $fn) = @_;
# print "In processDiv -- divID $divID\n";

  my $front = head("$divtitle",$prev,$next);	#construct HTML head
  my $back = "</body></html>\n";
  my $nav = navbar($prev, $next);

  # make a hash of the file containing each ID
  my $div1 = $div;
  $idfile{$divID} = $fn;
  while ($div1 =~ s/^.*?id="([^"]*)"//is) {
    $idfile{$1} = $fn;
  }

  return "$front$nav\n" . &thm2htm($div) . "\n$footnotes$nav$back";
}


#
# convert ThML from within a divn to HTML, with footnotes at end
#
sub thm2htm
{
  $_ = shift;
  $notenum = 1;
  $footnotes = "";
  $_ = &dumbquo($_);		#dumb down quotes, etc for HTML
  s|(<index[^>]*>)(.*?)(</index>)|&linkIndex($1,$2,$3)|gsie; #link index 
  s|(</?div)\d|$1|g;

  retag('attr',	      'p class="Attribution"', "p");
  retag('argument',   'p class="Argument"', "p");
  retag('meter',      'p class="meter"', "p");
  retag('sectionInfo','p class="sectionInfo"', 'p');
  retag('name',       'span class="Name"', 'span');
  retag('date',       'span class="Date"', 'span');
  retag('unclear',    'span class="unclear"', 'span');
  retag('l',          'p', 'p');
  retag('verse',      'table align=center class=verse><tr><td', 'table');

  # clean up verse a bit
  s|</table>\s*(<pb[^>]*>)?(\s*<img[^>]*>\s*)?\s*<table align=center class=verse>||gsi;
  
  # fix up URIs to point to this book or other volumes of series
  s|href="(.*?)"|&uri2url($1)|gsie;	#use real filenames in urls
  s|(<pb\s*n="([^"]*)"[^>]*>)|&pageref($1,$2)|gsie;	#page images

  # link scripture references to the bible gateway
  s|<scripRef(\s+[^>]*parsed="(.*?)"[^>]*)>(.*?)</scripRef>|&bglink($1,$2,$3)|gsie;
  s|(<note.*?>.*?</note>)|&note($1,$notenum)|gsie; # process footnotes
  s|\&line;|<br>|g;		       #change &line; to <br>
  s|(<p\s[^>]*>)(</p>)|$1&nbsp;$2|gs;  #add space to blank paragraphs

  #now for something really nasty: lists were generated as 
  #  <li><ul>: the <li> is required in valid HTML4.
  #But it looks terrible, with blank lines where they're not wanted.
  #This hack deletes that extra <li>, resulting in invalid (but better?) HTML
  s/<li>(<ul class="Index)/$1/g;
  $_ .= "</body></html>\n";

  return $_;
}


#
# process footnotes -- change to linked superscripted number, and
# store up the footnote bodies in $footnotes
#
sub note
{
  my $note=shift;
# print "Processing footnote $note -- number $notenum\n" if $debug;
  $footnotes = "\n<hr class=\"Note\">\n" if $footnotes eq "";

  $note =~ s|</?note[^>]*>||g;
  my $bref="<a class=\"Note\" name=\"_fnf$notenum\" " .
     "href=\"#_fnb$notenum\"><sup class=\"Note\">$notenum</sup></a>";
  $note =~ s|^(<p.*?>)|$1$bref |si;
  $note = "\n<div class=\"Note\" id=\"_fnf$notenum\">" . $note . "</div>\n";
  $footnotes .= $note;

  my $fref="<a class=\"Note\" name=\"_fnb$notenum\" " .
     "href=\"#_fnf$notenum\"><sup class=\"Note\">" . 
     $notenum++ . "</sup></a>";

# print "Returning: $fref\n";
  return $fref; 
}


#
# link scripture references to bible gateway
#
sub bglink
{
  my ($atts, $parsed, $text) = @_;
  my ($s, $bg, $version, $book, $fch, $fv, $tch, $tv, $id);

# print "in bglink: got atts=$atts parsed=$parsed text=$text\n";
  $atts =~ m|(id=".*?")|; $id=$1;
  $bg="";

  foreach $s (split /;/, $parsed) {
    ($version, $book, $fch, $fv, $tch, $tv) = split /\|/, $s;
    $bg .= $book;
    $bg .= "+$fch" if $fch;
    $bg .= ":$fv" if $fv;
    $bg .= "-" if $tch;
    $bg .= "$tch:" if $tch && $tch ne $fch;
    $bg .= $tv if $tv;
    $bg .= ",";
  }
  $bg =~ s/ //g;
  $bg = "<a href=\"http://bible.gospelcom.net/bible?passage=" . $bg ;
# $version = "Vulgate&language=Latin" if $version eq "VUL";
  $version = "" if $version eq "VUL";	#would like English vulgate...
  $bg .= "&version=$version" if $version;
  $bg .= "\" class=\"scripRef\" $id>$text</a>";
# print "  returning ref $bg\n";
  return $bg;
}


#------------tag-hack subroutines-----------------

#
# Process a head section: generalInfo, printSourceInfo, or electronicEdInfo
# First parameter is tag; second is contents of element
#
sub headsect
{
  my $section = shift;
  my $contents = shift;
  print "Processing $section\n" if $debug;
  my $result = "<h3>Information on the ";
  $result .= "Book" if $section eq "generalInfo";
  $result .= "Print Source" if $section eq "printSourceInfo";
  $result .= "Electronic Edition" if $section eq "electronicEdInfo";
  $result .= "</h3>\n";
  if ($section eq "generalInfo") {
    $result .= "<p class=\"HeadItem\"><b>Copyright</b>: $rights</p>\n";
    $result .= "<p class=\"HeadItem\"><b>CCEL Identifier</b>: $publisherID/";
    $result .= "$authorID/$bookID/$version</p>\n";
    $result .= "<p class=\"HeadItem\"><b>How to Reference This Edition</b>: ";
    $result .= "$DCpublisher, $DCdate, v$version, URL $URL</p>\n";
  }
  $contents =~ s|<([^>]*?)>(.*?)</\1>|&headItem($1,$2)|gse;
  $contents =~ s|<([^>]*?)/>|&emptyHeadItem($1)|gse;

  $result .= $contents . "\n\n";
  return $result;
}


#
#  Process one header element inside generalInfo, etc:
#  Modify element names to make nice titles: 
#    printSourceInfo --> Print Source Info 
#
sub headItem
{
  my $tag = shift;
  my $item = shift;
# print "HeadItem: processing $tag $item\n";
  return "" if $tag eq "bookID"  || $tag eq "authorID" ||
               $tag eq "version" || $tag eq "publisherID";
  return processDC($item) if $tag eq "DC";
  
  my $flowitem = ($tag eq "revisionHistory" || $tag eq "status" ||
                  $tag eq "editorialComments"); 

  $tag =~ s|([A-Z]{2})([a-z])|$1 $2|g;  #space after acronym
  $tag =~ s|([a-z])([A-Z])|$1 $2|g;	#add in spaces
  $tag = ucfirst($tag);			#make first letter upper case

  #tags have a content model of "Flow" may have their own <p>, etc.
  return "<p class=\"HeadItem\"><b>$tag</b>: $item</p>";
}


sub emptyHeadItem
{
  my $tag  = shift;
# print "EmptyHead: $tag\n";
  return "" if $tag =~ m/image/;
  return "<$tag>";
}


sub processDC
{
  my $DC=shift;
# print "Processing DC record: $DC\n" if $debug;

# convert to meta tags for HTML metadata
  my $DC1=$DC; 	
  $DC1 =~ s|</?DC>||gi;
  my ($tag,$content,$scheme);
  while ($DC1 =~ s|<((DC\.\w+).*?)>(.*?)</\2>||si)
  {
      $tag = $1;
      $content = $3;
      $tag =~ s|\s*sub="(\w+)"\s*|.$1|gsi;
      $scheme="";
      $scheme = " $1" if $tag =~ s|\s*(scheme\s*=\s*".*?")\s*||is;
      $meta .= "<meta name=\"$tag\"$scheme value=\"$content\">\n";
  }

  $DC =~ s|text/xml|text/html|;
  $DC =~ s|\s+sub="(\w+)"|.$1|g;			#for DC subelement
  $DC =~ s|<(DC[A-Za-z._]+)\s+scheme="(.*?)"\s*>(.*?)</DC.*?>|<tr><td>$1<td>$2<td>$3</tr>|gs;
  $DC =~ s|<(DC[A-Za-z._]+)\s*>(.*?)</DC.*?>|<tr><td>$1<td><td>$2</tr>|gs;
  my $ret = "<h3>Dublin Core Record</h3>\n";
  $ret .= "<center><table border=\"2\">\n";
  $ret .= "<tr><td><b>Element</b><td><b>Scheme</b><td><b>Content</b></tr>\n";
  $ret .= "$DC</table></center>\n";
  return $ret;
}
  


#
#given a title, return head of document, through <body>.
#
sub head
{
  my $title = shift;
  my $prev = shift;
  $prev = "TOC.htm" unless $prev;
  my $next = shift;
  $next = "TOC.htm" unless $next;
  my $h = "
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"
    \"http://www.w3c.org/TR/REC-html40/loose.dtd\">
<html><head>
<title>$title</title>
<link rel=\"stylesheet\" type=\"text/css\" href=\"$ssprefix/ss/ThML10.css\">
<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">
<link rel=\"prev\" type=\"text/html\" href=\"$prev\">
<link rel=\"toc\"  type=\"text/html\" href=\"TOC.htm\">
<link rel=\"next\" type=\"text/html\" href=\"$next\">
<script language=\"javascript\" src=\"$ssprefix/ss/util.js\">
</script>
</head><body>
";

  return $h;
}


#
#build a nav bar
#
sub navbar
{
  my $prev = shift;
  my $next = shift;
# print "In navbar: prev=$prev next=$next\n";
  $prev ||= "TOC.htm";

  my $nav  = "<p class=\"Center\">";
  $nav .= "<a href=\"$prev\">"
       .  "<img src=\"$ssprefix/pix/mroonppv.gif\" alt=\"Back\" border=\"0\"></a>";
  $nav .= "<a href=\"TOC.htm\">"
       .  "<img src=\"$ssprefix/pix/mroontoc.gif\" alt=\"Contents\" border=\"0\"></a>";
  $nav .= "<a href=\"$next\">"
       .  "<img src=\"$ssprefix/pix/mroonpnx.gif\" alt=\"Next\" border=\"0\"></a>";
  $nav .= "</p>\n";
  return $nav;
}


#
# make il, nl files with HTML to import into CCEL index, whats-new page.
#
sub makeLinks
{
  my $relurl = "htm/TOC.htm";
  $relurl = "htm/i.htm" if -f "htm/i.htm";
  $relurl = "htm/$bookID.htm" if $onefile;

  $authorID =~ m/^(.)/;
  my $url = "http://www.ccel.org/$1/$authorID/$series$bookID/$relurl";

  my ($day,$month,$year) = (localtime)[3,4,5];
  my $date = sprintf "%04d-%02d-%02d",$year+1900,$month+1,$day;

  open NL, ">nl" or die $!;
  print NL "\n$date<ul>\n<li>Added <a href=\"$url\">$title</a>\n";
  print NL "by $author.\n";
  print NL "Digitized by $digitized.\n" if $digitized;
  print NL "Typed by $typed.\n" if $typed;
  print NL "ThML markup by $thml.\n" if $thml;
  print NL "$status\n" if $status;
  print NL "</ul>\n";
  close NL;

  return $relurl;
}


#
# if you find a <pb n="xxx"> element, try to link it to a page image, which 
# should be located at png/nnnn=xxx.htm
#
sub pageref
{
  my $pb = shift;		#<pb> element
  my $page = shift;		#the page number of the <pb>
  my $pagenum = $page;
  $pagenum =~ s/^.*\.//;	#change i.3 to 3
  my $file = "";

  $file = "/php/disp.php?authorID=$authorID&bookID=$bookID" .
          "&page=$page&view=png" if $ccelhacks;	    #link to page-edit version
  if ($png) {					    # link static image
    $file = `ls png/*=$page.htm 2>/dev/null`;
    $file =~ s/\s+//gs;
#   print "Couldn't file file for page $page\n" unless $file;
    $file = "../" . $file if $file;
  }
  
  my $pref = "$pb\n<table class=marg align=left bgcolor=#660000><tr><td>\n";
  $pref .= "<p class=page>";
  $pref .= "$page" unless $file;
  $pref .= "<a class=page href=\"$file\">$page</a>" if $file;
  $pref .= "\n</table>\n";
  return $pref;
}


# this routine takes an <index>....</index> element and assumes that
# all the numbers listed therein are page numbers. They are linked to
# the Page_nnn ids of this document.
sub linkIndex
{
my $front = shift;
my $index = shift;
my $rear  = shift;

$index =~ s! (\d+)! <a class="TOC" href="|Page_$1">$1</a>!gsi;

return $front . $index . $rear;
}



#------------- index ------------------


sub index{
my $input = shift;

print "Generating indexes.\n";

#
# let's see if there are any other volumes linked here.
#
$input =~ s|\s*<!ENTITY\s+([^>]*?)\s+SYSTEM\s+"(.*?)">|&defEntity($1,$2)|gsie;
$input =~ s|(</ThML.body>)(.*?)(</ThML>)|$1$3|gsi;
my $vols = $2;
$vols =~ s/^\s+//gs;
$vols =~ s/\s+/:/gs;
$vols =~ s/[&;]//g;
my @volumes = split /:/, $vols;
print STDERR "volumes: ($#volumes) @volumes\n" if $#volumes>0;

$_ = $input;

# get default version and book, if any
my $versionDefault = m|<scripContext[^>]*version="(.*?)"|s;
my $bookDefault = m|<scripContext[^>]*passage="(\w*)|s;
my $authorID = m|<authorID\s*>(.*?)</authorID\s*>|s;
my $bookID = m|<bookID\s*>(.*?)</bookID\s*>|s;
my $url    = "/ccel/$authorID/$bookID.htm";
my $urlp   = "/ccel/$authorID/$bookID";

# time to delete <deleted> stuff so it doesn't get indexed
s|<deleted.*?</deleted>||gs;

s|(<insertIndex.*?>)|insertIndex($1)|gsie;
s|</insertIndex\s*>||gs;

return $_;

}	#end of sub index
  

#-----------------------index subroutines-----------------------

sub insertIndex
{
  my $tag = shift;
  my ($rec,$x) = ("","");
  my ($type) = $tag=~ m|type="(.*?)"|g;
  my $idx  = "\n<!-- Start of automatically inserted $type index -->\n";
  $idx .= "<div class=\"Index\">\n";
  my ($r, $s, $id, $name, $n, $passage, @entries, @index, %index, $inp);
 

  #--------------------------------------------------------------
  # make scripture-related indexes: scripRef, scripCom, scripture.
  # Make list of references and sort biblically. Name is book, 
  # chapter, verse list.
  #
  my ($oldbk,$bk,$bkid,$fch,$tch,$fv,$tv,$v,$i); 
# print STDERR "------Making $type index\n";

  my (@ventries) = ();	# now process other volumes
  if ($type =~ m|^scrip|) {
    (@entries) = m|(<$type[^>]*parsed[^>]*>)|gs;

    #now process the other files
    foreach $v (@volumes) {
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};
        (@ventries) = $inp =~ m|(<$type[^>]*parsed[^>]*>)|gs;
        my $n = $#ventries + 1;
        print STDERR " $n entries from $v\n" if $n;
        foreach $i (@ventries) { push @entries, "$v:$i"; }
        close IN;
    }

    my $num = $#entries + 1;
    print STDERR " Building scrip index -- $num entries in all\n";

    foreach $s (@entries) {             # process each entry
#     print "Found $s\n";
      $rec = &attributes($s);		# get reference attributes and parse
      my (@parsed) = split /;/, $rec->{"parsed"};

      foreach $r (@parsed) {            # for each resulting parsed entry,
#       print "  Parsed ref: $r\n";
        my $i = {};
        ($i->{"version"}, $i->{"book"}, $i->{"fch"}, $i->{"fv"}, 
         $i->{"tch"}, $i->{"tv"}) = split /\|/,$r;
        $i->{"bookID"} = $bookID{$i->{"book"}};
        ($i->{"url"},$x) = &geturl($s);
#       print "Adding to index: $i->{'version'}|$i->{'book'}|$i->{'fch'}\n";
        push @index, $i;                # add to index
      }
    }
 
    # sort scripture reference index
    sub byref { $a->{"bookID"} <=> $b->{"bookID"} or
                $a->{"fch"} <=> $b->{"fch"} or
                $a->{"fv"} <=> $b->{"fv"} or
                $a->{"tch"} <=> $b->{"tch"} or
                $a->{"tv"} <=> $b->{"tv"} or
                $a cmp $b };
    @index = sort byref @index;
 
#   print "scripRef index after sort: \n";
#   printHashArray(@index);
 
    my $continue=0;
    $oldbk="";
#   $idx .= "<ul class=\"bbook\">\n";

    foreach $s (@index) {              # add each entry to index
      $bk = $bookName[$s->{"bookID"}];
      $idx .= " </p>\n" if $continue and $oldbk ne $bk;
      $idx .= "<p class=\"bbook\">$bk</p>\n <p class=\"bref\">\n" 
              if $oldbk ne $bk;
      $oldbk=$bk;
      $continue=1;
      $idx .= " <a class=\"TOC\" href=\"$s->{'url'}\">".$s->{"fch"};
      $idx .= ":$s->{'fv'}" if $s->{'fv'};
      $idx .= "-$s->{'tv'}" if $s->{'fch'} eq $s->{'tch'};
      $idx .= "-$s->{'tch'}:$s->{'tv'}" 
                if $s->{'tv'} and $s->{'fch'} ne $s->{'tch'};
      $idx .= "</a>&#160;&#160;\n";
    }
    $idx .= " </p>\n" if $continue;
    $idx .= "</div>\n<!-- End of $type index -->\n\n";

#   print $idx;
    return "$idx\n";


  #--------------------------------------------------------------------
  # handle subject index entries.  Gather all <index /> elements, 
  # sort by subjects, then build hierarchical index.
  #
  } elsif ($type eq "subject") { 
    (@entries) = m|(<index[^>]*?/>)|gs;	#make list of all index entries

    my (@ventries) = ();	# now process other volumes
    foreach $v (@volumes) {
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};
        (@ventries) = $inp =~ m|(<index[^>]*/>)|gsi;
        my $n = $#ventries + 1;
        print STDERR " Finding subjects in $v -- $n entries\n" if $n;
        foreach $i (@ventries) { push @entries, "$v:$i"; }
        close IN;
    }

    my $n = $#entries + 1;
    print STDERR " Building subject index -- $n entries\n";
    foreach $s (@entries) {		#for each index entry
      my ($url, $vol) = &geturl($s);
      $vol = uc($vol) . ":" if $vol;
      $url =~ m/\|(.*)/;		# how should we identify a reference
      my $refid = $1 || "*";		# if not by the ID? seqential
      $refid =~ s/\.p.*//;		# integers, like footnotes?
#     print STDERR "  $s: url $url\n";
      $rec = &attributes($s);		#get references
      $rec->{"url"} = $url;
      $rec->{"name"} = $rec->{"title"};
      if (!$rec->{"name"}) {		#if no title, use vol:section
        $rec->{"name"} = $vol . $refid;
      }

      push @index, $rec;
    }

#   printHashArray(@index);                    #print out index entries 
    my ($s1, $s2, $s3, $s4, $new);
    $s1=$s2=$s3=$s4="";

    $SIG{__WARN__} = sub {};	#turn off warnings (uninitialized subjects)
    # sort subject index by subject4, subject3, etc.
    sub by_subj { $a->{"subject1"} cmp $b->{"subject1"} or
                  $a->{"subject2"} cmp $b->{"subject2"} or
                  $a->{"subject3"} cmp $b->{"subject3"} or
                  $a->{"subject4"} cmp $b->{"subject4"} or
                  $a->{"name"}    cmp $b->{"name"} }
    @index = sort by_subj @index;	#perl rocks!

    # output subject index as nested lists.
    # level is the depth of open lists; event is the lowest-level 
    # subject change.  For each new index entry, close off open lists
    # from level downto event, then open new lists as needed.

    my ($level, $event, $r);
    $level=1;
    $idx .= "<ul class=\"Index1\">\n";

    foreach $r (@index) {			#process all index entries
      $event=5;                                 #compute event level (5
      $event=4 if $s4 ne $r->{"subject4"};	#means no event, i.e. no 
      $event=3 if $s3 ne $r->{"subject3"};      #change in subjects
      $event=2 if $s2 ne $r->{"subject2"};
      $event=1 if $s1 ne $r->{"subject1"};
#     print "<br>lev$level event$event: $r->{'subject1'}|$r->{'subject2'}";
#     print "|$r->{'subject3'}|$r->{'subject4'}|$r->{'name'}\n";
      $s4=$r->{"subject4"}; $s3=$r->{"subject3"}; 
      $s2=$r->{"subject2"}; $s1=$r->{"subject1"}; 
         
      while ($event < $level) {	                #close off open lists
        $level--;
        $idx .= " "x$level . "</ul></li>\n";
      }

#     my $li = "";	#legal HTML requires <li><ul>, but that makes the
      my $li = "<li>";	#spacing of the list look bad! Extra blank line!
                        #we'll delete the extra <li> later, after validation
#     $idx .= " [First new subject: no new list needed]\n";
      if ($level==$event) {
        if ($level==1) {
          $idx .=" <li>$r->{'subject1'}</li>\n $li<ul class=\"Index2\">\n"; 
          $level++; 
        }
        elsif ($level==2) {
          $idx .="  <li>$r->{'subject2'}</li>\n  $li<ul class=\"Index3\">\n";
          $level++; 
        }
        elsif ($level==3) {
          $idx .="   <li>$r->{'subject3'}</li>\n   $li<ul class=\"Index4\">\n";
          $level++; 
        }
        elsif ($level==4) {
          $idx .="    <li>$r->{'subject4'}</li>\n    $li<ul class=\"Index5\">\n";
          $level++; 
        }
      }
        
#     $idx .= " [Now open any new needed lists]\n";
      if ($level==2 && $r->{'subject2'}) {
        $idx .= "  <li>$r->{'subject2'}</li>\n  $li<ul class=\"Index3\">\n"; 
        $level++; 
      }
      if ($level==3 && $r->{'subject3'}) {
        $idx .= "   <li>$r->{'subject3'}</li>\n   $li<ul class=\"Index4\">\n";
        $level++; 
      }
      if ($level==4 && $r->{'subject4'}) {
        $idx .= "    <li>$r->{'subject4'}</li>\n    $li<ul class=\"Index5\">\n";
        $level++; 
      }
        
      $idx .= "     <li><a class=\"TOC\" href=\"$r->{'url'}\">" .
                                               "$r->{'name'}</a></li>\n";
    }

    while ($level-- > 1) {
      $idx .= " "x$level . "</ul></li>\n"; }
    $idx .= " </ul>\n";
    $idx .= "</div>\n<!-- End of $type index -->\n\n";
    $SIG{__WARN__} = sub {warn $_[0];};		#turn warnings back on
    return $idx;

    
  #----------------------------------------------------------------
  #handle insertIndex type="contents", i.e. table of contents. If level
  #attribute is present, only index divs up to that level.
  } elsif (lc($type) eq "contents") {
    my $count=1;
    my (@urls, @levels, @names, $i);
    my ($maxlev) = $tag =~ m|level="(.*?)"|;
    (@entries) = m|(<div[1-7].*?>)|gs;

    my (@ventries) = ();	# now process other volumes
    foreach $v (@volumes) {
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};

        # find the title of this volume and put it in the TOC
        my ($title) = $inp =~ m|<DC.Title>([^<]*)</DC.Title>|si;
        push @entries, "$v:<div1 title=\"$title\" id=\"TitlePage\">";

        # now put all the <divn> entries in the TOC.
        @ventries = $inp =~ m|(<div[1-7].*?>)|gs;
        my $n = $#ventries + 1;
        print STDERR " Found $n entries in $v\n";
        foreach $i (@ventries) {
          $i =~ m|<div(\d)|;
          my $l=$1; my $l1 = $l + 1;	#increase TOC level by 1 
          $i =~ s|$l|$l1|s;
          push @entries, "$v:$i"; }
        close IN;
    }

    my $num = $#entries+1;
    print STDERR " Inserted TOC -- $num entries in all\n";
    
    foreach $s (@entries) {		   # for each <div element...
      my ($url,$x) = &geturl($s);
      my ($level) = $s =~ m|<div(\d)|;     # check if we're too deep
      next if (defined($maxlev) and ($level gt $maxlev));
      $levels[$count] = $level;

      my ($type) = $s =~ m|type="(.*?)"|;
      my ($n) = $s =~ m|n="(.*?)"|;	   # if there is a type and name,
      my ($name) = $s =~ m|title="(.*?)"|; # set name to type n. name
      $name ||= "";
      $name = $type." ".$n.". ".$name if $type and $n;
      $names[$count] = $name;
      $urls[$count++] = $url;
    }

    for ($i=1; $i<$count; $i++) {          # now make table of contents
      $idx .= "<p class=\"TOC$levels[$i]\"><a class=\"TOC\" " .
              "href=\"$urls[$i]\">" .
              "$names[$i]</a></p>\n";
    }
    $idx .= "</div>\n<!-- End of $type index -->\n\n";
    return $idx;

  #----------------------------------------------------------------
  # index of pages of print edition
  #
  } elsif ($type eq "pb") {
    (@entries) = m|(<pb[^>]*>)|gs;

    my (@ventries) = ();	# now process other volumes
    foreach $v (@volumes) {
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};
        (@ventries) = $inp =~ m|(<$type[^>]*>)|gs;
        my $n = $#ventries + 1;
        print STDERR " $n entries from $v\n" if $n;
        foreach $i (@ventries) { push @entries, "$v:$i"; }
        close IN;
    }

    my $num = $#entries + 1;
    print STDERR " Building page index -- $num entries\n";


  $idx .= "<p>";
  my $count=0;
  my $lastvol="xxx-fake-volume";
  foreach $s (@entries) {
    my ($url,$vol) = &geturl($s);
    if ($vol ne $lastvol) {
      $idx .= "</p><p class=\"bbook\">" .  uc($vol) 
           .  "</p>\n<p class=\"Index1\">\n";
       $lastvol = $vol;
    }
    ($id) = $s =~ m|.*?id="(.*?)"|s;
    ($n) = $s =~ m|n="(.*?)"|s;
    warn "Hey, no n= attribute for page $url vol $vol\n" unless $n;
    $idx .= "<a class=\"TOC\" href=\"$url\">$n</a>&nbsp;\n" if $n;
    $count++;
#   $idx .= "<br/>\n" if ($count % 10) == 0;
  }
  $idx .= "</p>\n</div>\n<!-- End of page index -->\n\n";

  return $idx;

  #----------------------------------------------------------------
  # 1. foreign language index.  Language given by lang=".." attribute.
  # 2. all other indexes.
  # After finding the <index> elements, handle them the same.
  #
  } elsif ($type eq "foreign") {
    my ($lang) = $tag =~ m/lang="(.*?)"/;
    (@entries) = m|(<foreign[^>]*lang="$lang"[^>]*>.*?</foreign>)|gsi;

    my (@ventries) = ();

      #now process the other files
      foreach $v (@volumes) {
#       print STDERR "Finding foreign ($lang) in $v\n";
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};
        (@ventries) = $inp =~ m|(<foreign[^>]*lang="$lang"[^>]*>.*?</foreign>)|gs;
        my $n = $#ventries + 1;
        print STDERR " $n entries from $v\n" if $n;
        foreach $i (@ventries) { push @entries, "$v:$i"; }
        close IN;
    }

    my $num= $#entries + 1;
    print STDERR " Building foreign($lang) index -- $num entries\n";

  #----------------------------------------------------------------
  } else {	#handle the rest: name, date, citation, etc.
    (@entries) = m|(<$type.*?</$type>)|gs;

    #now process the other files
    my (@ventries) = ();
    foreach $v (@volumes) {
#       print STDERR "Finding $type in $v\n";
        open IN, "<$entfile{$v}"; $inp = "";
        while ($i = <IN>) { $inp .= $i;};
        (@ventries) = $inp =~ m|(<$type.*?</$type>)|gs;
        my $n = $#ventries + 1;
        print STDERR " $n entries from $v\n" if $n;
        foreach $i (@ventries) { push @entries, "$v:$i"; }
        close IN;
    }

    my $num= $#entries + 1;
    print STDERR " Building $type index -- $num entries\n";
  }

  # at this point @entries contains all relevant index entries.
  # find pertinent info, sort, and return index.
  # (cases that already did this already returned.)
  foreach $s (@entries) {
#   print "Processing entry---------\n$s\n--------\n";
    my ($url, $vol) = &geturl($s);
    $vol = uc($vol);
    ($id) = $s =~ m|.*?id="(.*?)"|s;
    ($name) = $s =~ m|.*?>(.*)<.*?|s;
    $name = $1 if $s =~ m|title="(.*?)"|s;
    ($n) = $s =~ m|n="(.*?)"|s;
    $name = $n unless $name;
    $name =~ s/id=".*?"//g;
    $name =~ s/(>[^<]{60,60}[^<]*?[a-zA-Z.,;]+)[^<]*/$1.../gsi;	  #shorten long bits
    $name .= " ($vol)" if $vol;
    $index{$name} = $url;
#   print "-->name $name\n";
  }
  
  $idx .= "<ul class=\"Index1\">\n";
  foreach $s (sort keys %index) {
    $idx .= " <li><a class=\"TOC\" href=\"$index{$s}\">$s</a></li>\n";
  }
  $idx .= "</ul>\n</div>\n<!-- End of $type index -->\n\n";
  return $idx;
}


#
# this routine finds the url for a reference from volID:<tag>
#
sub geturl
{
  my $s = shift;
# print "Geturl: s=$s";
  my ($m,$v,$id,$url) = ("","");
  $m = $s =~ s|^([^<:]*):||;
  $v = $1 if $m;
  $s =~ m|id="([^"]*)"|s;
  $id = $1;
  $s =~ m|target="([^"]*)"|s;
  $id = $1 if $1;
  $url = "/ccel/$authorID/$bookID.htm|$id";
  $url = "/ccel/$authorID/$bookID/$v.htm|$id" if $v;
# print " --> $url\n";
  warn "returning null url\n" unless $url;
  return ($url,$v);
}

  

# this sub, used for debugging, prints contents of an array of hashes
sub printHashArray
{
  print "-------------\n";
  my ($role, $i);

  for $i ( 0 .. $#_ ) {
    print "$i is { ";
    for $role ( keys %{ $_[$i] } ) {
      print "$role=$_[$i]{$role} ";
    }
    print "}\n";
  }
  print "-------------\n"
}



#
# Remember each entity definition (with SYSTEM identifier)
#
sub defEntity
{
  my $ent  = shift;
  my $path = shift;
  print STDERR "Found entity $ent, path $path\n";
  warn "Couldn't find entity $ent\n" unless -f $path;
  $entfile{$ent} = $path;
  return "";
}



#------------ parsescr ---------------

sub parsescr {
print "Parsing scripture references.\n";
my $input = shift;
$refcount = 0;

sub bylength { length($b) <=> length($a) }
foreach $b (sort bylength keys %bookID) {
  push @bookaliases, $b;
}

# get default version and book, if any (bug: should really parse through
# and see when defaults apply, not just use them for whole file...)
#
$versionDefault = $input =~ m|<scripContext[^>]*version="(.*?)"|;
my ($bookDefault) = $input =~ m|<scripContext[^>]*passage="(^ )*|;

# first we should copy enclosed scripture passage in scripRef tag to
# passage="..." attribute, if it isn't already there.
$input =~ s|(<scripRef>)(<span\s+class="MsoEndnoteReference">[^<]*</span>)|$2$1|gsi;
$input =~ s|(<scripRef[^>]*>)<span[^>]*>([^<]*)</span>(</scripRef>)|$1$2$3|gsi;
$input =~ s|(<scripRef[^>]*>)<span[^>]*>([^<]*)</span>(</p>)(</scripRef>)|$1$2$4$3|gsi;
$input =~ s|(<scripRef[^>]*)>([^<]*?)(</scripRef>)|$1 passage="$2">$2$3|gsi;
$input =~ s|(<scripRef[^>]*passage="[^>]*?"[^>]*)passage="[^>]*?">|$1>|gsi;

# now parse the passage in the passage attribute and put result in 
# parsed attribute.
$input =~ s#(<(scripRef|scripCom|scripture)[^>]*>)#&parsetag($1)#gse;

print "Processed $refcount scripture references.\n"; 
return $input;
}


sub parsetag
{
  my $tag = shift;
  $refcount++;
  print "--------\nIn parsetag: got $tag\n" if $debug;

  $tag =~ s|&#8211;|-|g;
  $tag =~ s|\s+| |gs;
  my ($passage) = $tag =~ m|passage="(.*?)"|;
  my ($version) = $tag =~ (m|version="(.*?)"|);
  $version ||= $versionDefault || "";
  my $parsed = parse($passage,$version) if $passage;
  $tag =~ s|\s*(/?>)| parsed="$parsed"$1| if $parsed;
  print "Parsetag: returning $tag\n" if $debug;
  return $tag;
}



#-------------------------subroutines------------------
#
# this subroutine finds all of the attributes of the form xxx="yyy" and
# returns them as a reference to a hash.
sub attributes
{
  my $tag = shift;
  my $rec = {};
  my $s;

  while ($tag =~ s|(\w+)="(.*?)"||s) {		#find all attributes
    $rec->{$1} = $2; }

  return $rec;
}
  

#parse a scripref, returning parsed format, 
#(version|book|fch|fv|tch|tv) [; (version|book|fch|fv|tch|tv)*]
sub parse
{
  my $passage = shift;
  my $orig = $passage;
  my $version = shift;
  my ($parsed, $chaps, $chap, $bookcomma);
  print "Parse: got $version $passage\n" if $debug;
  my $bk = $bookName[$bookID{$bookDefault}] if $bookDefault;
  my ($fch, $tch, $fv, $tv);
  $fch=$tch=$fv=$tv=0;

  $passage =~ s/ff//g;			#delete ff in v. 37ff
  $passage =~ s/\s*sq+\.?//g;		#delete sqq.
  $passage =~ s/etc\.?//g;		#delete etc
  $passage =~ s/[\.,]$//;		#delete trailing dot or comma
  while (length($passage)) {
    $passage =~ s/\s*and\s*//;
    $passage =~ s/^III\s*/3/;
    $passage =~ s/^II\s*/2/;
    $passage =~ s/^I\s*/1/ unless $passage =~ m|^Is|; #don't mangle Isaiah
    $passage =~ s/^([1-3])\s+/$1/;
    $passage =~ s/^cf.\s*//;

    foreach $b (@bookaliases) {		#search for book among bookaliases
      $chaps ||= 0;
      if ($passage =~ s|^$b||i) {
        $bk = $bookName[$bookID{$b}];
        $chaps = $chapters[$bookID{$b}];
        print "  Found $b => $bookName[$bookID{$b}], $chaps chs\n" if $debug;
      }
    }
    $passage =~ s/^[. ]*//;

    if ($passage =~ s#^(verse|ver|vs|vv)s?\.?\s*##) {
      print "Found vv. --  looking for a verse\n" if $debug;
      $chap=$fch;
      }
    if ($passage =~ s#^(chapter|chapt|chap|ch|c)s?\.?\s*##) {
      print "Found chs. --  looking for a chapter\n" if $debug;
      $chap=0;
      }

    print "  Passage remaining: $passage\n" if $debug;

    # if the upcoming stuff is a roman numeral, arabacize
    if ($passage =~ s|^([clxvi]+)\.?\s*|&rom2arab($1)."."|gsie) {
      $passage =~ s|\.$||;
      $passage =~ s|\.;|;|;
      $passage =~ s|\.?--\s*([clxvi]+)|"--".&rom2arab($1)|gsie;
      $passage =~ s|\.?-\s*([clxvi]+)|"--".&rom2arab($1)|gsie;
      $passage =~ s|--(\d+)\. (\d+)|-$1:$2|;
      }

    print "  Passage after rom2arab: $passage\n" if $debug;
  
    # look for references like 3:16-4:2
    if ($passage =~ s|^\s*(\d+)[:.](\d+)\s*-\s*(\d+)[:.](\d+)\s*||) {
      print "  case 1. ch:v-ch:v\n" if $debug;
      $fch=$1; $fv  = $2; $tch=$3; $tv=$4; }
    
    # look for 3:16-18
    elsif ($passage =~ s|^\s*(\d+)[:.](\d+)\s*-\s*(\d+)\s*||) {
      print "  case 2. ch:v-v\n" if $debug;
      $fch=$1; $fv=$2; $tch=$1; $tv=$3;}

    # look for 3:16
    elsif ($passage =~ s|^\s*(\d+)[:.](\d+)\s*||) {
      print "  case 3. ch:v\n" if $debug;
      $fch=$1; $fv=$2; $tch=0; $tv=0; }

    # look for Phm. 5-7 (one-chapter book)
    elsif ($chaps==1 && ($passage =~ s#^(\d+)-(\d+)\s*##)) {
      print "  case 4. 1ch bk, v-v\n" if $debug;
      $fch=1; $fv=$1; $tch=1; $tv=$2; }

    # look for John 5-7 (expecting a verse, e.g John 3:3,5-7)
    elsif ($chap && ($passage =~ s#^(\d+)-(\d+)\s*##)) {
      print "  case 5 v-v.\n" if $debug;
      $fv=$1; $tv=$2; $tch=$fch; }

    # look for John 3--4 (multi-chapter books)
    elsif ($chaps > 1 && $passage =~ s|^(\d+)--(\d+)\s*||) {
      print "  case 6. ch--ch\n" if $debug;
      $fch=$1; $tch=$2; }

    # look for John ch. 3-4 (multi-chapter books)
    elsif (!$chap && $chaps > 1 && $passage =~ s#^(\d+)--?(\d+)\s*##) {
      print "  case 7. ch. ch-ch\n" if $debug;
      $fch=$1; $tch=$2; }
   
    # John 5 (multi-chapter books, not expecting a verse, e.g. John 3:16; 5
    # then set bookcomma: even if we get a comma, we're expecting a book.
    # e.g. Psalms 75, 76, and 77.
    elsif (!$chap && $chaps > 1 && $passage =~ s#^(\d+)\s*##) {
      print "  case 8. ch\n" if $debug;
      $fch=$1; $fv=0; $tch=0; $tv=0; $bookcomma=1; }
   
    # John 5 (expecting a verse, e.g. John 3:3, 5
    elsif ($chap && ($chaps > 1) && $passage =~ s#^(\d+)\s*##) {
      print "  case 9. v\n" if $debug;
      $fv=$1; $tch=0; $tv=0; $chap=0; }

    # Phm. 3 or Phm. v.3 (one-chapter book)
    elsif ($chaps==1 && $passage=~s#^(\d+)\s*##) {
      print "  case 10. (1ch bk) v\n" if $debug;
      $fch=1; $fv=$1; $tch=0; $tv=0; }

    # otherwise, punt
    else {
      warn "Couldn't parse scripref $orig, near $passage\n";
      print "Couldn't parse scripref $orig, near $passage\n" if $debug;
      return "";
    }

    print "  found $version|$bk|$fch|$fv|$tch|$tv\n" if $debug;
    $parsed .= "$version|$bk|$fch|$fv|$tch|$tv;";
    
    $passage =~ s|^\s*||;
    if ($passage =~ s|^;\s*||) {
      print "Found ';' -- looking for chapter\n" if $debug;
      $fv=0; 
      $chap=0;
    }
    if ($passage =~ s|^,\s*||) {
      if (!$bookcomma) {
        print "Found ',' --  looking for a verse\n" if $debug;
        $chap=$fch;
      }
      else
      {
        print "Found ',', but looking for a chapter anyway\n" if $debug;
        $chap=0;
        $bookcomma=0;
      }
    }
  }
  $parsed =~ s/;$//;
  return $parsed;
}

#
# convert roman numerals 1..399 to arabic
#
sub rom2arab
{
  my $rom = shift;
# print "rom2arab: $rom ->";
  $rom = lc($rom);
  $rom =~ s/xc/lxxxx/;
  $rom =~ s/xl/xxxx/;
  $rom =~ s/ix/viiii/;
  $rom =~ s/iv/iiii/;
  my $arab = 0;
  while (length($rom)>0) {
    $rom =~ s/^(.)//;
    my $digit = $1;
    $arab += 100 if $digit eq "c";
    $arab += 50 if $digit eq "l";
    $arab += 10 if $digit eq "x";
    $arab += 5 if $digit eq "v";
    $arab += 1 if $digit eq "i";
  }
# print " $arab\n";
  return $arab;
}


#----------------- ThMLutil.pm ---------------------


#
#given a div start tag, this subroutine returns the id, title, 
#and filename for the division.  Dies if the division had no ID.
#
#Title chosen is the type and n if both are present (e.g. Chapter 3),
#followed by the title attribute if present.  If neither of those were
#present, the ID is used.
#
sub getName
{
  my $div = shift;
  my $title = "";
# print STDERR "Getting title from division $div\n";
  die "A division had no ID: $div\n" unless $div =~ m|id="([^"]*)"|;
  my $id = $1;
  my ($n) = $div =~ m|n="([^"]*?)"|;
  my ($type) = $div =~ m|type="([^"]*?)"|s;
  $title = "$type $n. " if $type and $n; 
  my ($titleatt) = $div =~ m|title="([^"]*?)"|s;
  if ($titleatt) {
    $title .= $titleatt if $title;
    $title = $titleatt unless $title;
  }
  $title ||= $id;
  my $filename = "$id.htm";
  $filename =~ s/\s//gs;
# print STDERR "  returning title $title\n";
  return ($id, $title, $filename);
}
 

#
# delete all tags in parameter
#
sub detag
{
  my $in = shift @_;
  $in =~ s|<[^>]*>||gs;
  return $in;
}


# change the tag for a character style to something else:
# _delete --> delete start tag, end tag, and text between
# _unescape_delete --> unescape and delete tags
# _detag --> remove tags

sub chartag
{
  my $styname = shift;
  my $tagname = shift;
  my $tagend  = shift;

  if ($tagname eq "_unescape_detag") {
    s|<STRING CHARSTYNAME="$styname".*?>(.*?)</STRING>|&unescape($1)|gsei; }
  elsif ($tagname eq "_delete") {
    s|<STRING CHARSTYNAME="$styname".*?>.*?</STRING>||gsi; }
  elsif ($tagname eq "_detag") {
    s|<STRING CHARSTYNAME="$styname".*?>(.*?)</STRING>|$1|gsi; }
  elsif ($tagname eq "_comment") {
    s|<STRING CHARSTYNAME="$styname".*?>(.*?)</STRING>|<!-- $1 -->|gsi; }
  else {
    s|<STRING CHARSTYNAME="$styname"(.*?)>(.*?)</STRING>|<$tagname$1>$2</$tagend>|gsi; }
}


# handle a paragraph style:
# _unescape_detag: unescape and remove tags
# _detag: remove tags
# _delete: delete tags and text
# otherwise, switch to a new tag name

sub partag
{
  my $styname = shift;
  my $tagname = shift;
  my $tagend  = shift;

  if ($tagname eq "_unescape_detag") {
    s|<P STYLENAME="$styname".*?>(.*?)</P>|&unescape($1)|gsie; }
  elsif ($tagname eq "_delete") {
    s|<P STYLENAME="$styname".*?>.*?</P>||gsi; }
  elsif ($tagname eq "_detag") {
    s|<P STYLENAME="$styname".*?>(.*?)</P>|$1|gsi; }
  elsif ($tagend eq "") {
    s|<P STYLENAME="$styname"(.*?)>(.*?)</P>|<$tagname$1>$2|gsi; }
  else {
    s|<P STYLENAME="$styname"(.*?)>(.*?)</P>|<$tagname$1>$2</$tagend>|gsi; }
}


# change one tag to another
sub retag
{
  my $tagname = shift;
  my $tagrep  = shift;
  my $tagend  = shift;

  if ($tagrep eq "_detag")
    { s|</?$tagname\b.*?>||gsi; }
  elsif ($tagrep eq "_delete")
  {
    s|<$tagname\b.*?>.*?</$tagname>\s*||gsi;
    s|<$tagname\b.*?>\s*||gsi;
  }
  elsif ($tagrep eq "_delete_attributes")
  {
    s|(<$tagname\b).*?(/?>)|$1$2|gi;
  }
  else
  {
    s|<$tagname\b(.*?)>|<$tagrep$1>|gsi;
    s|</$tagname\b(.*?)>|</$tagend$1>|gsi;
  }
}


#escape notes so they don't get processed later
sub escape 
{
  my $stuff = shift;
  $stuff =~ s/</\&less-than;/g;
  return $stuff;
}


#change &lt; to <, &gt; to >, &amp; to &
sub unescape
{
  my $stuff = shift;
  $stuff =~ s/(\&lt;)(.*?)(\&gt;)/$1.&dumbquo($2).$3/gse;
  $stuff =~ s/\&lt;/</g;
  $stuff =~ s/\&gt;/>/g;
  $stuff =~ s/\&amp;/\&/g;
  return $stuff;
}


#
#unsmarten (dumbify?) quotes and apostrophes because
#netscape is unsmart enough not to understand them.
#
sub dumbquo
{
  my $stuff = shift;
  $stuff =~ s/\&[rl]dquo;/"/g;
  $stuff =~ s/\&[rl]squo;/'/g;
  $stuff =~ s/\&apos;/'/g;
  $stuff =~ s/\&mdash;/--/g;
  $stuff =~ s/\&ndash;/-/g;
  $stuff =~ s/\&\#8209;/-/g;
  $stuff =~ s/\&\#8212;/--/g;
  $stuff =~ s/\&\#8211;/-/g;
  $stuff =~ s/\&\#821[67];/'/g;
  $stuff =~ s/\&\#822[01];/"/g;
  return $stuff;
}


# convert a hex unicode code to a decimal escape
sub escapehex
{
  my $code = shift;
  my $dec = hex $code;
  return "&#$dec;";
}


#convert greek (charset=161) to decimal unicode escapes
sub unigreek
{
  my $gk=shift;
# print STDERR "Greek passage: $gk\n";
  $gk =~ s|(\d+)|$1+720|ge;
# print STDERR "...converted to $gk\n";
  return $gk;
}

#
#normalizeDivs: delete </divn>s and replace where needed.
#
sub normalizeDivs
{
my $doc=shift;
my $level=1;
my ($stuff, $divtag, $l);

print "In normalizeDivs\n" if $debug;

$doc =~ s|</div\d[^>]*>||gs;		# delete </divn>s
$doc =~ s|^(.*?<div1[^>]*>)||s;		# delete up to first <div1>
my $out=$1;

while ($doc =~ s|(.*?)(<div(\d)[^>]*>)||s)
    {					# find next <divn>, process div
    ($stuff, $divtag, $l) = ($1, $2, $3);
    $out .= $stuff;			# output stuff

#   print "1. level=$level l=$l\n";
    while ($level >= $l) {		# output any needed </div>s
        $out .= "</div$level>";
	$level--;
#       print "2. level=$level l=$l\n";
    }
    $out .= $divtag;		# output next <divn> tag
    $level = $l;
#   print "3. level=$level l=$l\n";
}

while ($level > 0) {
    $doc =~ s|(</ThML.body>)|</div$level>$1|;
    $level--;
}
$out .= $doc;

return $out;
}


#----------------------------------------------------------
#
# Identify subroutines -- add ids to many tags.
# This code can be run more than once on a file without
# ill effect -- and it has been greatly speeded up, so
# it can be called once in index and once in thm2htm.
#
# ncrease code is also here, to add n= attributes to
# <divn> tags, making each one more than the previous.
#
# bugs: if a <divn> has n attributes that can't be incremented, e.g.
# n="Two", results are undesirable. n attributes should be arabic or
# roman numerals.
#


#----------------identify: add IDs---------------------------
#
sub identify 
{
my $in = shift;

print "In identify\n" if $debug;

# change n attribute of PB tags to Page_n id
$in =~ s|(<pb[^>]*n=")([^"]*)("[^>]*?)\s*(/?>)|$1$2$3 id="Page_$2"$4|gs;

# change all existing n="xx" to upper case, so we can add lower case roman
# numerals later on.
$in =~ s|(<div[^>]*n=")([^"]*)(")|$1 . uc($2) . $3|gsie;

# find all ids already in use
while ($in =~ m|id="([^"]*)"|g) { $ids_used{$1} = 1; }

# find head, body, tail
$in =~ m|^(.*<ThML.body>)(.*)(</ThML.body>.*)$|is;
my ($head, $div0, $tail) = ($1, $2, $3);

return $head . &identifyDiv($div0,"0","") . $tail;
}


#---------------process a division -- add ids ---------------
#
# identifyDiv($div, $level, $prefix).  A divn consists of some cdata 
# followed by 0 or more div(n+1)s.
# --> make sure all divs have n attributes as needed
# --> keep track of where we are (3.1.5, etc.). This is $prefix
# --> process embedded divs recursively
# This function does not receive only the contents of a div$level,not
# the surrounding tags.
#
sub identifyDiv
{
  my ($div, $level, $pre) = @_;
  my $hasdivs = $div =~ m|<div\d|;
  return &addid($div,$pre) unless $hasdivs;

  $div =~ s|(^.*?)(<div\d)|$2|si;
  my $result = &addid($1,$pre);

  my ($n,$oldn,$id,$pre2) = ("i","","");
  while ($div =~ s|(.*?)(<div(\d)[^>]*>)(.*?)(</div\3>)||si) {
    my ($stuff, $start, $newlevel, $content, $end) = ($1, $2, $3, $4, $5);
    $result .= $stuff;
    my $ntag = $start =~ m|n="([^"]*)"|;
    $oldn = $n;
    $n = $1 if $ntag;
    $pre2 = "$pre.$n" if $pre;
    $pre2 = $n unless $pre;
    $pre2 =~ s/\s//gs;
#   $start =~ s|\s*>| n="$n">|s if !$ntag and $ncrease;
    $n = &inc($n);
    $oldn = &inc($oldn);
    $n = $oldn unless $n;

    $start =~ s|\s*id="([^"]*)"||;
    $start =~ s|\s*>| id="$pre2">|s;

    $content = &identifyDiv($content, $newlevel, $pre2);
    $result .= "$start$content$end";
  }
  return $result;
}

  
#
# increment a number whether arabic or roman
#
sub inc				
{
  my $n = shift;

  if ($n =~ m|^[mdclxvi]*$|i)
    { $n = &incroman($n); }
  elsif ($n =~ m|^[0-9]+$|)
    { $n++; }
  else
    { $n = ""; }

  return $n; 
} 


#
# increment lower- or upper-case roman numerals. Add one and carry.
# Doesn't know what to do with MMMM, MMMMM, etc.
#
sub incroman	
{
  my $r = shift;
  my $one = "i";
  $one = "I" if $r =~ m/^[MDCLXVI]*$/;
  $r .= $one;;

  # now perform carries
  $r =~ s|iiii|iv|;
  $r =~ s|IIII|IV|;
  $r =~ s|ivi|v|;
  $r =~ s|IVI|V|;
  $r =~ s|viv|ix|;
  $r =~ s|VIV|IX|;
  $r =~ s|ixi|x|;
  $r =~ s|IXI|X|;
  $r =~ s|xxxx|xl|;
  $r =~ s|XXXX|XL|;
  $r =~ s|xlx|l|;
  $r =~ s|XLX|L|;
  $r =~ s|lxl|xc|;
  $r =~ s|LXL|XC|;
  $r =~ s|xcx|c|;
  $r =~ s|XCX|C|;
  $r =~ s|cccc|cd|;
  $r =~ s|CCCC|CD|;
  $r =~ s|cdc|d|;
  $r =~ s|CDC|D|;
  $r =~ s|dcd|cm|;
  $r =~ s|DCD|CM|;
  $r =~ s|cmc|m|;
  $r =~ s|CMC|M|;

  return $r;
}


#------------ add tag ids --------------
# 
# This subroutine adds an id attribute to each element after the
# first <div1>. The id is of the form xxx.xxx.xxx.pyy.zz, where
# each xxx identifies a div, yy is the paragraph number in the
# division, and zz is the element number.
#


sub addid
{
  my ($in,$pre) = @_;
# print STDERR "addid input length:" . length($in);
  my ($p,$t,$out,$tag,$id) = ("0","0","","","");

  while ($in =~ s|^([^<]*)(<[^>]*>)||s) {
    $out .= $1;
    $tag = $2;

    if (($tag =~ m/^(<i>|<b>|<br|<hr|<sup|<font|<note|<span|<!)/) || #unwanted tags
        ($tag =~ m|^</|) ||		#end tag
        ($tag =~ m|id="|)) {		#tag already had an ID
        $out .= $tag;
        next;
    }

    if ($tag =~ m|(<p[^>]*)>|s)
    {
      $p++;				#increment paragraph counter
      $t = "0";				#reset tag counter to 0
      $id = "$pre.p$p";
      if ($ids_used{$id}) {
        print STDERR "HEY -- $id was already used! (2)\n" if $ids_used{$id};
        my $idsuffix = "_1";
        while ($ids_used{$id . $idsuffix}) { $idsuffix++; }
        $id .= $idsuffix;
        print STDERR "    -- let's use $id instead.\n";
      }
    } else { 				#any other tag, possibly <  />
      $t++;				#increment tag counter
      $id = "$pre.p$p.$t";
      if ($ids_used{$id}) {
        print STDERR "HEY -- $id was already used!\n" if $ids_used{$id};
        my $idsuffix = "_1";
        while ($ids_used{$id . $idsuffix}) { $idsuffix++; }
        $id .= $idsuffix;
        print STDERR "    -- let's use $id instead.\n";
      }
    }
    $tag =~ s|\s*(/?>)| id="$id"$1|si;
    $out .= $tag;
    $ids_used{$id} = 1;
  }

  $out .= $in;

# print STDERR "-->" . length($out) . "\n";
}


#----------------------------------------------------------------
# ncrease <pb> tags

sub ncrease
{
$_ = shift;
#first determine the number of pages per image, if there are images.
my $col = 0;
my $output = "";
my ($pb, $oldhref, $foundhref, $newn, $oldn);
my $href = "";

# now loop through $_, stopping to process each <pb...> element.
while (m|^(.*?)(<pb.*?/>)|s)
  {
  s|^(.*?)(<pb.*?/>)||s;
  $output .= $1;
  my $pb = $2;
# print STDERR "$pb --> ";

  #
  #this section handles hrefs. 
  #If there is not an href, but there was one previously, inc previous one.
  #If there is an href, remember it, and if it is the same as previous one, 
  # set $col to 2. (2 pages per image; this is second column)
  #
  $oldhref = $href;		
  $foundhref = "";
  $foundhref = $1 if $pb =~ m|href="(.*?)"|;
  if (!$foundhref && $oldhref)
    { 
#   print STDERR "noref oldref";
    ($href, $col) = incpage($oldhref, $col); 
    $pb =~ s|/>| href="$href" />|;
    }
  elsif (length($foundhref)>0)
    {
#   print STDERR "href";
    $href=$foundhref;
    $col=2 if $href eq $oldhref;
    }
# print STDERR " col=$col ";

  #this section increments n, the page number
  my $n = "";
  $n = $1 if $pb =~ m|n="(.*?)"|;
  if ($n)
    { $newn = $n; }
  else
    { $newn = &inc($oldn); }
  $oldn = $newn;
  $pb =~ s|/>| n="$newn" />| unless $pb =~ m|n=|;

  #increment href, the page image

# print STDERR "$pb\n";
  $output .= $pb;
  }
  $output .= $_;
  return $output;
}


#  smart-increment a picture href
#
#  Two sequences are supported: xx001.gif, xx002.gif, etc and xx001a.gif, 
#  xx001b.gif, xx002a.gif, xx002b.gif, etc. In addition, there may be one
#  or two pages per image.
#
#  This subroutine takes a filename and $col=0, 1, or 2.  If 0, there is
#  one page per image.  If 1, there are two pages per image, and this is
#  the first.  If two, there are two pages per image, and this is the
#  second.
#
#  The return values are the new $filename and the new $col value.
#
sub incpage	
{
  my $filename = shift;
  my $col = shift;

  return ($filename, 2) if $col==1; 
				#if there's another page on this pic, use it.

  $col=1 if $col==2;
  if ($filename =~ m|a\.[^\.]+$|)
    { $filename =~ s|a(\.[^\.]+$)|b$1|; }
  else
    {
    $filename =~ s|b(\.[^\.]+$)|a$1|;

    $filename =~ m|([0-9]+)[^0-9]*$|;
    my $oldn = $1;
    my $newn = $1 + 1;
    while ( length($newn) < length($oldn) )
      {$newn = "0" . $newn; }

    $filename =~ s|$oldn|$newn|;
    }

  return ($filename, $col);
}


sub divcrease
{
  my $in = shift;
  my ($out, $oldn, $n, $div, $level, $oldlevel) = ("","","","","","");

  while ($in =~ m|^(.*?)(<div\d.*?>)|s)
    {
    $in =~ s|^(.*?)(<div\d[^>]*>)||s;
    $out .= $1;
    $div = $2;
    $oldn = $n;
    $n = "";
    $n = $1 if $div =~ m|n="(.*?)"|;
    $oldlevel = $level;
    $level = "";
    $level = $1 if $div =~ m|<div(.)|;

#   print " oldn=$oldn n=$n   oldlevel=$oldlevel level=$level\n";
    if ($level eq $oldlevel and $oldn and !$n)
    {
      $n = &inc($oldn);
      $div =~ s|(<div.*?)>|$1 n="$n" >|s if $n;
#     print "ncrease: div=$div oldn=$oldn n=$n ndiv=$div\n";
    }
    $out .= $div;
  }

  $out .= $in;
  return $out;
}



#
# read file of bible book names and abbreviations
#
sub readbookID
{
  my $bookIDinfo=&bookID;

  foreach my $f (split /\n/, $bookIDinfo) {
    chomp $f;
    $f =~ s|#.*$||;
    next if $f =~ m|^\s*$|;

    my @names  = split /:/, $f;
    my $bkID   = shift @names;
    my $bkname = shift @names;
    $bookName[$bkID] = $bkname;
    $chapters[$bkID] = shift @names;
    $bookID{$bkname} = $bkID;
    foreach my $n (@names) {
      $bookID{$n} = $bkID; }

#        print "Book ID=$bkID name=$bookName[$bkID]; chaps=$chapters[$bkID]\n";
#        print "Aliases: ";
#        foreach my $n (keys %bookID) {
#          print "key $n -> $bookID{$n}\n";
#          print " $n" if $bookID{$n} eq $bkID;
#        }
  }
}


sub bookID
{
return "
1:Genesis:50:Ge:Gen:Gene:Genes:Gn
2:Exodus:40:Exod:Exo:Ex
3:Leviticus:27:Levit:Levi:Lev:Le
4:Numbers:36:Numb:Num:Nu:Nm
5:Deuteronomy:34:Deuter:Deut:Deu:De
6:Joshua:34:Josh:Jos
7:Judges:21:Judg:Jud:Ju:Jdg:Jd
8:Ruth:4:Ru
9:1 Samuel:31:1Sam:1Sa:1Samuel
10:2 Samuel:24:2Sam:2Sa:2Samuel
11:1 Kings:22:1King:1Ki:1Kings
12:2 Kings:25:2King:2Ki:2Kings
13:1 Chronicles:29:1Chron:1Chro:1Chr:1Ch
14:2 Chronicles:36:2Chron:2Chro:2Chr:2Ch
15:Ezra:10:Ezr:Ez:1Esdras:1Esdr:1Esd:1Es
16:Nehemiah:13:Nehemiah:Nehem:Neh:Ne:2Esdras:2Esdr:2Esd:2Es
17:Esther:10:Esth:Est:Es
18:Job:42:Jo
19:Psalms:150:Psal:Psa:Ps:Psalm
20:Proverbs:31:Prov:Pro:Pr
21:Ecclesiastes:12:Eccles:Eccl:Ecc:Ec
22:Song of Songs:8:Song:Song of Solomon:Song of Sol.:SS:So:SSong:Cant:Canticles
23:Isaiah:66:Isa:Is:
24:Jeremiah:52:Jerem:Jere:Jer:Je
25:Lamentations:5:Lament:Lamen:Lam:La
26:Ezekiel:48:Ezek:Eze:Ez
27:Daniel:12:Dan:Da
28:Hosea:14:Hos:Ho
29:Joel:3:Joe
30:Amos:9:Am
31:Obadiah:1:Obad:Oba:Ob
32:Jonah:4:Jon
33:Micah:7:Mic:Mi
34:Nahum:3:Nah:Na
35:Habakkuk:3:Habak:Hab:Ha
36:Zephaniah:3:Zeph:Zep
37:Haggai:2:Hag:Ha
38:Zechariah:14:Zech:Zec
39:Malachi:4:Malach:Malac:Mal
40:Matthew:28:Matth:Matt:Mat:Mt
41:Mark:16:Mar:Mk:Mr
42:Luke:24:Luk:Lu:Lk
43:John:21:Joh:Jn
44:Acts:28:Act:Ac
45:Romans:16:Rom:Ro
46:1 Corinthians:16:1Corinth:1Corin:1Cor:1Co:1Corinthians
47:1 Corinthians:13:2Corinth:2Corin:2Cor:2Co:2Corinthians
48:Galatians:6:Galat:Gal:Ga
49:Ephesians:6:Ephes:Eph
50:Philippians:4:Philip:Phil:Phi:Ph:Php:Philipp
51:Colossians:4:Colos:Colo:Col:Co:Coloss
52:1 Thessalonians:5:1Thess:1Thes:1The:1Th
53:2 Thessalonians:3:2Thess:2Thes:2The:2Th
54:1 Timothy:6:1Ti:1Tim:1Timothy
55:2 Timothy:4:2Timothy:2Tim:2Ti
56:Titus:3:Tit:Titu
57:Philemon:1:Philem:Phile:Phm
58:Hebrews:13:Heb:He:Hebr
59:James:5:Jas:Jam
60:1 Peter:5:1Pet:1Pe:1Peter
61:2 Peter:3:2Pet:2Pe:2Peter
62:1 John:5:1Joh:1Jo:1John:1Jn
63:2 John:1:2Joh:2Jo:2Jn:2John
64:3 John:1:3Joh:3Jo:3Jn:3John
65:Jude:1:Ju
66:Revelation:22:Revel:Rev:Re:Apocalypse:Apoc
69:Tobit:2:Tob:To
70:Judith:2:Judit:Judi:
72:Wisdom:2:Wisdom:Wisd:Wis:Wisdom of Solomon
73:Sirach:2:Ecclesiasticus:Ecclus:Wisdom of Jesus Son of Sirach:Sirach:Sir:Si
74:Baruch:2:Bar:Ba
75:Letter of Jeremiah:2
76:Prayer of Azariah:1
77:Susanna:1:Sus:Su
78:Bel:1:Bel:Be:Bel and Drag:Bel and the Dragon
79:1 Maccabees:2:1Maccabees:1Maccab:1Macc:1Mac:1Ma
80:2 Maccabees:2:2Maccabees:2Maccab:2Macc:2Mac:2Ma
81:1 Esdras:2:1Esdras:1Esdr:1Esd:1Es
82:Prayer of Manasseh:2:Manasseh:Manas:Man
83:2 Esdras:2:2Esdras:2Esdr:2Esd:2Es
84:3 Maccabees:2:3Maccabees:3Maccab:3Macc:3Mac:3Ma
85:4 Maccabees:2:4Maccabees:4Maccab:4Macc:4Mac:4Ma
86:Psalm 151:1
";
}
