use strict;
use warnings;
use JSON;
use File::Find qw(finddepth);
use Encode qw(decode);

#### START OF GLOBAL VARS

my $fh;  # Output file handle
my $imgDirectory = 'C:/Users/Owner/My Website/img/covers';
my @thingers = ();   # [ { "type":"altars", "count":35, "super":"furniture", "aliases":[...] },... ]
my $respJsonData;	# The response data from the current JSON file.

#### END OF GLOBAL VARS

#### START OF MAIN PROGRAM ####

my @files = <./json/*.json>;
foreach my $file (@files) {
	$respJsonData = loadJson($file);
	makeThingerPage();
}
makeIndexPage();

#### END OF MAIN PROGRAM ####

sub loadJson {
   my $inname = $_[0];
   my $jsondata = '';
   open(my $jinfh, "<", $inname) || die("can't open $inname: $!");
   print "*** reading $inname ... ";
   while ( <$jinfh> ) {
     $jsondata .= $_; 
   }
   close $jinfh;
   print "DONE!\n";

   print "*** parsing $inname ... ";
   print STDERR "*** parsing $inname ...\n";
   $jsondata =~ s/^\x{ef}\x{bb}\x{bf}//;  # decode_json doesn't like these leading bytes, the "Byte Order Mark" aka BOM.
   my $hashref = decode_json $jsondata;
   print "DONE!\n";
   print STDERR "*** $inname parsed!\n";
   return $hashref;
}

sub makeIndexPage {
   open($fh, ">:encoding(UTF-8)", "C:/Users/Owner/My Website/things/index.html");
   print $fh "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n";
   print $fh "<meta charset=\"UTF-8\">\n";
   print $fh "<meta name=\"Author\" content=\"David Welbourn\">\n";
   print $fh "<title>IF Things</title>\n";
   print $fh "</head>\n\n";
   print $fh "<body>\n<h1><img src=\"../img/kaclogo.svg\" width=\"50\" height=\"50\" alt=\"\" style=\"vertical-align:middle\"> <span id=\"h1\">IF Things</span></h1>\n\n";
   print $fh "<p>Let's examine things in works of interactive fiction! What sorts of things do you want to look at?</p>\n";

   print $fh "<hr><h2>Things by Category</h2>\n";

   # First we need to assemble a list of top supercategories.
   my %allsupers = ();
   foreach my $r (@thingers) {
	   if (exists($r->{'super'})) {
		   my $super = $r->{'super'};
		   $allsupers{$super} = { 'thingers' => [] } unless exists($allsupers{$super});
		   # Now load the supercategory.
		   push @{$allsupers{$super}->{'thingers'}}, $r;
	   }
	   if (exists($r->{'supers'})) { foreach my $super (@{$r->{'supers'}}) {
		   $allsupers{$super} = { 'thingers' => [] } unless exists($allsupers{$super});
		   # Now load the supercategory.
		   push @{$allsupers{$super}->{'thingers'}}, $r;
	   }}
   }

   # Report 'em!
   print $fh "<ul style=\"column-count:3\">\n";
   my @superkeys = sort {lc($a) cmp lc($b)} keys %allsupers;
   foreach my $k (@superkeys) {
      print $fh "<li><details><summary>" . ($k eq 'zzz' ? 'other' : $k) . "</summary><ul>\n";
      foreach my $thinger (@{$allsupers{$k}->{'thingers'}}) {
         my $p = $thinger->{'type'};
         my $c = $thinger->{'count'};
         print $fh " <li><a href=\"$p.html\">$p</a> ($c)</li>\n";
      }
      print $fh "</ul></details></li>\n";
   }
   print $fh "</ul>\n\n";
   
   # Create a list of index-items.
   my %allindexes = ();
   foreach my $r (@thingers) {
	   $allindexes{$r->{'type'}} = { 'count' => $r->{'count'} };
	   if (exists($r->{'aliases'})) { foreach my $alias (@{$r->{'aliases'}}) {
		   $allindexes{$alias} = { 'see' => $r->{'type'} };
	   }}
   }

   print $fh "<hr><h2>Things in Alphabetical Order</h2>\n";
   print $fh "<ul style=\"column-count:3\">\n";
#   foreach my $r (@thingers) {
#      my $p = $r->{'type'};
#      my $c = $r->{'count'};
#      print $fh "<li><a href=\"$p.html\">$p</a> ($c)</li>\n";
#   }
	foreach my $k (sort {lc($a) cmp lc($b)} keys %allindexes) {
		if (exists($allindexes{$k}->{'count'})) {
			my $c = $allindexes{$k}->{'count'};
			print $fh "<li><a href=\"$k.html\">$k</a> ($c)</li>\n";
		}
		elsif (exists($allindexes{$k}->{'see'})) {
			my $s = $allindexes{$k}->{'see'};
			print $fh "<li><i>$k</i>: see <a href=\"$s.html\">$s</a></li>\n";
		}
	}
   print $fh "</ul>\n\n";

   print $fh "<hr><h2>About this Thinger project</h2>\n";
   print $fh "<p>I don't expect to stay around forever, so I'm also publishing the raw data and program that I used to create these pages.";
   print $fh " If you wish to continue (update, modify, expand) this project or make a similar project and not want to start from scratch, please feel free to use my materials.";
   print $fh " Crediting me would be nice, please and thank you.";
   print $fh " In the meantime, I retain the right to maintain my own version of this project as long as I'm willing and able to do it.</p>\n";
   print $fh "<ul>\n";
   print $fh "<li><code><a href=\"things.json.zip\">things.json.zip</a></code> contains all the JSON datafiles in this project.</li>\n";
#   print $fh "<li><code><a href=\"index.json\">index.json</a></code> contains the index data in JSON format.</li>\n";
#   print $fh "<li>Raw datafiles in JSON format:<ul>\n";
#   foreach my $r (@{$idxJsonData->{'things'}}) {
#      my $p = $r->{'type'};
#      print $fh "<li><code><a href=\"$p.json\">$p.json</a></code></li>\n";
#   }
#   print $fh "</ul></li>\n";
   print $fh "<li><code><a href=\"Thinger.pl\">Thinger.pl</a></code> is the Perl program that reads the JSON files and spits out the webpages.";
   print $fh " It also peeks at an image directory on my computer to see what cover art images are available.</li>\n";
   print $fh "<li><code><a href=\"About Thinger.html\">About Thinger.html</a></code> is my documentation page for this project.</li>\n";
   print $fh "</ul>\n";
   print $fh "<p>All my JSON files use UTF-8 encoding. This project was begun in September 2018. HUGE thank you to all you authors of interactive fiction. You are all amazing. Thank you.</p>\n";
   print $fh "<p style=\"text-align:right\">&mdash; David Welbourn</p>\n";
   doFooter('index');
   print $fh "</body>\n</html>\n";
   close $fh;
}

sub makeThingerPage {
   my $thType = $respJsonData->{'type'};
   my $outFilename =  "C:/Users/Owner/My Website/things/" . $thType . ".html";
   my $thCount = 0;
   
   my @cameos = ();
   my @defaults = ();
   my @defaultContainers = ();
   my @defaultDevices = ();
   my @deflecteds = ();
   my @empties = ();
   my @noExamines = ();
   my @synonyms = ();
   my @unimportants = ();

   open($fh, ">:encoding(UTF-8)", $outFilename);
   print $fh "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n";
   print $fh "<meta charset=\"UTF-8\">\n";
   print $fh "<meta name=\"Author\" content=\"David Welbourn\">\n";
   print $fh "<title>" . ucfirst($thType) . " in Interactive Fiction</title>\n";
   print $fh "<link rel=\"stylesheet\" type=\"text/css\" href=\"resp.css\">\n";
   insertJS();
   print $fh "</head>\n\n";
   print $fh "<body id=\"_top\">\n<h1><img src=\"../img/kaclogo.svg\" width=\"32\" height=\"32\" alt=\"\" style=\"vertical-align:middle;margin-left:3px;margin-right:0.5em;border-style:none\">" . ucfirst($thType) . ' in Interactive Fiction';
   print $fh "<span style=\"float:right;\">";
   print $fh "<a href=\"#_top\"><img src=\"../img/top20x20.png\" height=\"20\" width=\"20\" alt=\"[top]\" title=\"top\" style=\"vertical-align:middle;\"></a>";
   print $fh " <img src=\"../img/menu20x20.png\" height=\"20\" width=\"20\" alt=\"[menu]\" title=\"menu\" style=\"vertical-align:middle;margin-right:0.5em;\" onclick=\"toggle_vmenu()\">";
   print $fh "</span></h1>\n\n";
   print $fh "<div style=\"height:36px;\"><!-- spacer under the h1 --></div>\n\n";
   print_vmenu();   # The vertical menu with the sort menuitems.

   # Intro
	if (exists($respJsonData->{'icon'}) and exists($respJsonData->{'icon'}{'img'})) {
		print $fh "<img class=\"icon\" src=\"../img/icons/" . $respJsonData->{'icon'}{'img'} . "\" alt=\"\">\n";
	}
	print $fh "<div>";
	if (exists($respJsonData->{'about'})) {
		my $s = $respJsonData->{'about'};
		print $fh "<p>" if (substr($s,0,1) ne '<');
		print $fh $s;
		print $fh "</p>" if (substr($s,0,1) ne '<');
		print $fh "\n";
	}
	if (exists($respJsonData->{'icon'}) and exists($respJsonData->{'icon'}{'attrib'})) {
		print $fh "<p><small>" . $respJsonData->{'icon'}{'attrib'};
		if (exists($respJsonData->{'icon'}{'lic'})) {
			my $lic = $respJsonData->{'icon'}{'lic'};
			if ($lic eq "CCBY3.0") {
				print $fh " (<a href=\"https://creativecommons.org/licenses/by/3.0/\">CCBY3.0</a>)";
			}
			elsif ($lic eq "PD") {
				print $fh " (<a href=\"https://creativecommons.org/publicdomain/mark/1.0/\">Public Domain</a>)";
			}
			else {
				print $fh " $lic";
			}
		}
		print $fh "</small></p>\n";
	}
	print $fh "</div>\n<hr>\n";


   # Main: Gather info
   my @rawInfo = ();
   foreach my $wid (keys %{$respJsonData->{'works'}}) {
      my $work = $respJsonData->{'works'}->{$wid};

      # First, determine if this game is one that we're interested in.
      # Fatally incomplete entries will be skipped over.
      my $ok = 1;
	  my $nHasDesc = 0;
	  my $nListAs = 0;
	  if (exists($work->{'dont-list'})) { $ok = 0; }
      if (!exists($work->{'title'})) { $ok = 0; }
      elsif ($work->{'title'} eq '') { $ok = 0; }
      if (!exists($work->{'things'})) { $ok = 0; }
      elsif (scalar @{$work->{'things'}} == 0) { $ok = 0; }
      else {
         foreach my $th (@{$work->{'things'}}) {
#            if (!exists($th->{'name'})) { $ok = 0; }
#            elsif ($th->{'name'} eq '') { $ok = 0; }
#            if (!exists($th->{'desc'})) { $ok = 0; }
#            elsif ($th->{'desc'} eq '') { $ok = 0; }
#            elsif ($th->{'desc'} =~ /\[TODO\]/) { $ok = 0; }
			if (!exists($th->{'name'})) { next; }
			if ($th->{'name'} eq '') { next; }
			if (!exists($th->{'loc'})) { next; }
			if ($th->{'loc'} eq '') { next; }
			if (exists($th->{'desc'}) and $th->{'desc'} ne '' and $th->{'desc'} !~ /\[TODO\]/) { $nHasDesc++; }
			if (exists($th->{'list-as'})) { $nListAs++; }
         }
      }
	  
	  # Record old list-as cases here.
	  if (exists($work->{'title'}) && exists($work->{'list-as'})) {
		my $title = $work->{'title'};
		my $listAs = $work->{'list-as'};
		my $sort = title2sort($title);
		my $name = title2html($title);
		$name .= ' (' . $work->{'sfx'} . ')' if exists($work->{'sfx'});
		$name .= ' (' . calcReleaseYear($wid, $work) . ')';
		my $listRec = { 'sort' => $sort, 'name' => $name };
		if (exists($work->{'list-note'})) {
			$listRec->{'note'} = $work->{'list-note'};
		}
		if ($listAs eq 'cameo') { push @cameos, $listRec; }
		elsif ($listAs =~ /^default/) { push @defaults, $listRec; }
		elsif ($listAs eq 'deflected') { push @deflecteds, $listRec; }
		elsif ($listAs eq 'empty') { push @empties, $listRec; }
		elsif ($listAs eq 'no-examine') { push @noExamines, $listRec; }
		elsif ($listAs eq 'synonym') { push @synonyms, $listRec; }
		elsif ($listAs eq 'unimportant') { push @unimportants, $listRec; }
	  }
	  
	  # Record new list-as cases here.
	  if ($ok and $nListAs > 0) {
		 my $title = $work->{'title'};
		 
		 my $sort = title2sort($title);
		 my $name = title2html($title);
		 $name .= ' (' . $work->{'sfx'} . ')' if exists($work->{'sfx'});
		 $name .= ' (' . calcReleaseYear($wid, $work) . ')';

         foreach my $th (@{$work->{'things'}}) {
			 if (exists($th->{'list-as'})) {
				my $listRec = { 'sort' => $sort, 'name' => $name,  };
				$listRec->{'objname'} = $th->{'name'} if exists($th->{'name'});
				$listRec->{'loc'} = $th->{'loc'} if exists($th->{'loc'});
				$listRec->{'for'} = $th->{'for'} if exists($th->{'for'});
				$listRec->{'note'} = $th->{'note'} if exists($th->{'note'});
				
				my $listAs = $th->{'list-as'};
				if ($listAs eq 'cameo') { push @cameos, $listRec; }
				elsif ($listAs =~ /^default/) { push @defaults, $listRec; }
				elsif ($listAs eq 'deflected') { push @deflecteds, $listRec; }
				elsif ($listAs eq 'empty') { push @empties, $listRec; }
				elsif ($listAs eq 'no-examine') { push @noExamines, $listRec; }
				elsif ($listAs eq 'synonym') { push @synonyms, $listRec; }
				elsif ($listAs eq 'unimportant') { push @unimportants, $listRec; }
				# else ignore that instance.
			 }
		 }
	  }

      if ($ok and $nHasDesc > 0) { # Add a record to @rawInfo.
         my $resp = '';
		 foreach my $th (@{$work->{'things'}}) {
			 if (exists($th->{'desc'}) && $th->{'desc'} ne '') {
				 $resp = $th->{'desc'};
				 last;
			 }
		 }
         my $relyear = calcReleaseYear($wid, $work);
         my $revyear = 9999 - $relyear;
         my $r = { 'id' => $wid, 'title' => $work->{'title'}, 'things' => $work->{'things'},
                   's1' => title2sort($work->{'title'}),
                   's2' => resp2sort($resp),
                   's3' => $relyear . ' ' . title2sort($work->{'title'}),
                   's4' => $revyear . ' ' . title2sort($work->{'title'}) };
         if (exists($work->{'sfx'})) { $r->{'sfx'} = $work->{'sfx'}; }
         if (exists($work->{'x'})) { $r->{'x'} = $work->{'x'}; }
         $r->{'year'} = $relyear;
         push @rawInfo, $r;
         $thCount += scalar @{$work->{'things'}};
      }
   }

   # Sorting
   my @sortedInfo = sort { $a->{'s2'} cmp $b->{'s2'} } @rawInfo;
   my $counter = 1000;
   foreach my $r (@sortedInfo) {
      $r->{'s2'} = $counter++;  # Replace s2 field with a 4-digit number to sort by.
   }
   @sortedInfo = sort { $a->{'s3'} cmp $b->{'s3'} } @sortedInfo;
   $counter = 1000;
   foreach my $r (@sortedInfo) {
      $r->{'s3'} = $counter++;  # Replace s3 field with a 4-digit number to sort by.
   }
   @sortedInfo = sort { $a->{'s4'} cmp $b->{'s4'} } @sortedInfo;
   $counter = 1000;
   foreach my $r (@sortedInfo) {
      $r->{'s4'} = $counter++;  # Replace s4 field with a 4-digit number to sort by.
   }
   @sortedInfo = sort { $a->{'s1'} cmp $b->{'s1'} } @sortedInfo;
   $counter = 1000;
   foreach my $r (@sortedInfo) {
      $r->{'s1'} = $counter++;  # Replace s1 field with a 4-digit number to sort by.
   }

   # Main: Output
   print $fh "<ul id=\"respList\">\n";
   foreach my $r (@sortedInfo) {

      # Begin the article.
      my $id = $r->{'id'};
      print $fh "<li id=\"$id\"";
      print $fh " data-s1=\"" . $r->{'s1'} . "\"" if exists($r->{'s1'});
      print $fh " data-s2=\"" . $r->{'s2'} . "\"" if exists($r->{'s2'});
      print $fh " data-s3=\"" . $r->{'s3'} . "\"" if exists($r->{'s3'});
      print $fh " data-s4=\"" . $r->{'s4'} . "\"" if exists($r->{'s4'});
      print $fh ">\n";

      # Optional cover art.
      my $img = '';   
      if (-e "$imgDirectory/$id.png") { $img = 'png'; }
      elsif (-e "$imgDirectory/$id.jpg") { $img = 'jpg'; }
      elsif (-e "$imgDirectory/$id.gif") { $img = 'gif'; }
      if ($img ne '') {
         print $fh "<img class=\"cover80\" src=\"../img/covers/$id.$img\" alt=\"\">\n";
      }

      # Begin the entry.
      print $fh "<div class=\"entry\">\n";
      print $fh "<p class=\"statusline\">" . title2html($r->{'title'});
      print $fh " <i>(" . $r->{'sfx'} . ")</i>" if defined($r->{'sfx'});
      print $fh " (" . $r->{'year'} . ")" if exists($r->{'year'});
      print $fh "</p>\n";


      # Print the response(s).
      my $nthings = 0;
      foreach my $th (@{$r->{'things'}}) {
		 if (exists($th->{'list-as'})) { next; }
		 if (!exists($th->{'desc'}) || $th->{'desc'} eq '') { next; }
		 
         print $fh "<hr>\n" if $nthings > 0;
         print $fh "<p class=\"in\"><b>&gt; ";
         if (exists($r->{'x'})) {  # Some games don't understand 'x' for 'examine'.
            print $fh $r->{'x'};
         }
         else {
            print $fh "x";
         }
         print $fh " " . $th->{'name'} . "</b>";
         print $fh " <i>(@ " . $th->{'loc'} .")</i>" if exists($th->{'loc'}) && $th->{'loc'} ne '';
         print $fh "</p>\n";
         print $fh "<p class=\"out\">" if (substr($th->{'desc'},0,1) ne '<');
         $th->{'desc'} =~ s/^<p>/<p class="out">/ ;
         print $fh $th->{'desc'};
         print $fh "</p>" if (substr($th->{'desc'},0,1) ne '<');
         print $fh "\n";
		 if (exists($th->{'note'})) {
			print $fh "<div class=\"note\">" . $th->{'note'} . "</div>\n";
		 }
         $nthings++;
      }

      # End the entry and list item.
      print $fh "</div>\n</li>\n\n";
   }
   # Add the listAs blocks, if any.
   if (scalar @cameos > 0) { addListAsBlock( 'Cameo appearance instances', 9991, \@cameos ); }
   if (scalar @defaults > 0) { addListAsBlock( 'Default response instances', 9992, \@defaults ); }
   if (scalar @defaultContainers > 0) { addListAsBlock( 'Default container response instances', 9993, \@defaultContainers ); }
   if (scalar @defaultDevices > 0) { addListAsBlock( 'Default device response instances', 9994, \@defaultDevices ); }
   if (scalar @deflecteds > 0) { addListAsBlock( 'Deflected examining instances', 9995, \@deflecteds ); }
   if (scalar @empties > 0) { addListAsBlock( 'Empty response instances', 9996, \@empties ); }
   if (scalar @noExamines > 0) { addListAsBlock( 'No examining supported instances', 9997, \@noExamines ); }
   if (scalar @synonyms > 0) { addListAsBlock( 'Synonyms of other things instances', 9998, \@synonyms ); }
   if (scalar @unimportants > 0) { addListAsBlock( 'Unimportant response instances', 9999, \@unimportants ); }
   
   print $fh "</ul>\n\n";   # End of respList.

   # Remember the number of things, the super(s), and aliases.
    my $r = { "type" => $thType, "count" => $thCount };
	if (exists($respJsonData->{'super'})) {
		$r->{'super'} = $respJsonData->{'super'};
		# push @thingers, { "type" => $thType, "count" => $thCount, "super" => $respJsonData->{'super'} };
	}
	elsif (exists($respJsonData->{'supers'})) {
		$r->{'supers'} = $respJsonData->{'supers'};
		# push @thingers, { "type" => $thType, "count" => $thCount, "supers" => $respJsonData->{'supers'} };
	}
	else {
		$r->{'super'} = 'zzz';
		# push @thingers, { "type" => $thType, "count" => $thCount, "super" => 'zzz' };
	}
	$r->{'aliases'} = $respJsonData->{'aliases'} if exists($respJsonData->{'aliases'});
	push @thingers, $r;

   # Outro
#   print $fh "<hr>\n";
#   if (exists($v->{'outro'})) {
#      my $s = $v->{'outro'};
#      print $fh "<p>" if (substr($s,0,1) ne '<');
#      print $fh $s;
#      print $fh "</p>" if (substr($s,0,1) ne '<');
#      print $fh "\n";
#   }
#   print $fh "<p>Do you want to see the ";
#   my @otherCommands = ();
#   foreach my $command (sort keys %{$idxJsonData->{"commands"}}) {
#      push @otherCommands, $command if $command ne $commandKey;
#   }
#   my $n = 1; my $nCommands = scalar(@otherCommands);
#   foreach my $command (@otherCommands) {
#      print $fh "or " if $n == $nCommands;
#      print $fh "<a href=\"$command.html\">". uc($command) . "</a>";
#      print $fh "," if $n != $nCommands;
#      print $fh " ";
#      $n++;
#   }
#   print $fh " page next?</p>";

   doFooter($thType);
   print $fh "</body>\n</html>\n";
   close $fh;
}

sub addListAsBlock {
	my ($groupHeader, $sortNum, $works) = @_;
	print $fh "<li id=\"zzzzz_$sortNum\"";
    print $fh " data-s1=\"$sortNum\" data-s2=\"$sortNum\" data-s3=\"$sortNum\" data-s4=\"$sortNum\">\n";
	print $fh "<div class=\"entry\">\n";
    print $fh "<p class=\"statusline\" style=\"background-color:paleturquoise;color:black\">$groupHeader</p>\n";
	print $fh "<small><ul>\n";
	my @sorted = sort { $a->{'sort'} cmp $b->{'sort'} } @{$works};
	foreach my $r (@sorted) {
		print $fh "<li>" . $r->{'name'};
		print $fh ": " . $r->{'objname'} if exists($r->{'objname'});
		print $fh " \x{2261} " . $r->{'for'} if exists($r->{'for'});
		print $fh " @ " . $r->{'loc'} if exists($r->{'loc'});
		print $fh ".";
		print $fh " NOTE: " . $r->{'note'} if exists($r->{'note'});
		print $fh "</li>\n";
	}
	print $fh "</ul></small>\n";
	print $fh "</div>\n</li>\n\n";
}

sub doFooter {
   my $pageName = $_[0];
   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
   my $dd = substr('0' . $mday,-2);
   my $mmm = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')[$mon];
   my $yyyy = 1900 + $year;
   print $fh "<footer>\n";
   print $fh "<hr>\n";
   print $fh "<p style=\"font-size:small;text-align:center;\">\n";
   if ($pageName eq 'index') {
      print $fh " <a href=\"../ifindex.html\">Interactive Fiction</a>\n";
   }
   else {
      print $fh " <a href=\"index.html\">IF Things</a>\n";
   }
   print $fh " <span style=\"float:left;\">Last updated: $dd $mmm $yyyy</span>\n";
   print $fh " <span style=\"float:right;\">davidwelbourn(a)hotmail*com</span>\n";
   print $fh "</p>\n";
   print $fh "</footer>\n";
}

sub print_vmenu {
   my $code = <<'END_VMENU';
<div class="menupopup">
<ul class="vmenu">
<li><a href="javascript:sortList('data-s1');">Sort by Title</a></li>
<li><a href="javascript:sortList('data-s2');">Sort by Response</a></li>
<li><a href="javascript:sortList('data-s3');">Sort by Year</a></li>
<li><a href="javascript:sortList('data-s4');">Sort by Reverse Year</a></li>  
</ul>
</div>
END_VMENU
   print $fh $code;
}

sub title2sort {
   my $s = $_[0];
   $s = lc($s);
   if ($s =~ /^(.*)\|(.*)$/) {
      $s = $2 . ' (' . $1 .')';
   }
   # TODO: replace accented characters with unaccented ones.
   return $s;
}

sub title2html {
   my $s = $_[0];
   $s =~ s/\|//g;
   $s =~ s/&/&amp;/g;
   $s =~ s/</&lt;/g;
   $s =~ s/>/&gt;/g;
   $s =~ s/\[or\]/|/g;
   return $s;
}

sub s2id {
   my $s = $_[0];
   $s = lc($s);
   $s =~ s/ /_/g;
   $s =~ s/\//_/g;
   return $s;
}

sub calcReleaseYear {
   my ($wid, $work) = @_;
   if (exists($work->{'year'})) {
      return $work->{'year'};
   }
   else {
      my $yy = substr($wid, 5, 2);  # scrape the 2-digit year from the id.
      if ($yy eq 'xx' || $yy eq '') { return '0000'; }
      elsif ($yy ge '70') { return '19' . $yy; }
      else                { return '20' . $yy; }
   }
}

sub insertJS {
   my $jsCode = <<'END_JSCODE';
<script>
function toggle_vmenu() {
   var e = document.getElementsByClassName("menupopup")[0];
   if (e.style.visibility === 'visible') { e.style.visibility = 'hidden'; }
   else { e.style.visibility = 'visible'; }
}

function sortList(key) {
   var list = document.getElementById('respList');
   var nodes = list.children;
   // Bubble sort
   for (var i = 0; i < nodes.length - 1; i++) {
      for (var j = i + 1; j < nodes.length; j++) {
         var iNode = nodes[i];
         var jNode = nodes[j];
         if (iNode.getAttribute(key) > jNode.getAttribute(key)) {
            if (iNode.swapNode) {
                iNode.swapNode(jNode);
            }
            else {
                var kNode = iNode.nextSibling;
                list.replaceChild(iNode, jNode);
                list.insertBefore(jNode, kNode);
            }
         }
      }
   }
   // Hide the vmenu
   document.getElementsByClassName("menupopup")[0].style.visibility = 'hidden';
}
</script>

END_JSCODE
   print $fh $jsCode;
}

# Convert a response string into something I can sort by.
sub resp2sort {
   my $s = $_[0];
   $s = lc($s);
   $s =~ s/\n/ /gs;
#   $s =~ s/<i>\[.*?\]<\/i>//g;  # remove my embedded comments. (old markup!)
   $s =~ s/<ins>.*?<\/ins>//g;   # remove my embedded comments. (new markup!) 
   $s =~ s/<.*?>//g;   # remove all HTML tags.
   $s =~ s/&[a-z]+;/ /g;   # remove &nbsp; etc.
   # TODO: remove accents on characters.
   $s =~ s/\s+/ /g;    # replace whitespace sequences with single space.
   $s =~ s/^[^a-z0-9]+//;   # remove leading non-alphanumerics.
   if (length($s) > 50) {   # chop down to 50 characters if longer.
      $s = substr($s,0,50);
   }
   return $s;
}

