#!/software/perl-5/bin/perl -w
# links to subsections
# top-level listing of papers and talks should look like:
#    * <title, linked> (with <other authors>)
#      where it appeared (perhaps multiple times like higher-order concurrency)
use strict;

my $base = "http://daisy.uwaterloo.ca/~eddemain/";
my ($indexfile, $ctrfile, $logfile, $abstractfile) =
    ("index.html", "index.ctr", "index.log", "abstract.html");
my $debugging = 0;
if ($debugging) {
    $indexfile = "new-index.html";
}

my %suffixes = (
    "" => "HTML",
    ".ps" => "PostScript",
    ".ps.gz" => "gzip'd PostScript"
);
my @suffix_order = ("", ".ps", ".ps.gz");

my %complement = ( "(" => '\)', "{" => '}', "\"" => '"' );

my %at_types = (
  "article" => ["Journal article", 0,
    'author, title, journal, volume, number, date, pages, publisher. note'
  ],
  "inproceedings" => ["Conference paper", 0,
    'author, title, "in" booktitle, address, date, pages, publisher. note'
  ],
  "mastersthesis" => ["Master's thesis", 0,
    'author, title, "Master\'s thesis", school, address, date. note'
  ],
  "techreport" => ["Technical reports", 0,
    'author, title, "Technical report" number, institution, address, date. note'
  ],
  "conferencetalk" => ["Conference talk", 1,
    'author, title, series, conference, address, date. note',
    "This section only lists talks at conferences without proceedings.  See also <a href=\"${base}papers/#inproceedings\">conference papers</a>."
  ],
  "invitedtalk" => ["Invited talk", 1,
    'author, title, "Invited talk", series, institution/conference, address, date. note'
  ],
);
my @kinds = (
    { # Papers
        "name"  => "Paper",
        "dir"   => "papers",
        "file"  => "paper",
        "order" => ["article", "inproceedings", "techreport", "mastersthesis"]
    },
    { # Talk
        "name"  => "Talk",
        "dir"   => "talks",
        "file"  => "talk",
        "order" => ["invitedtalk", "conferencetalk"]
    }
);

my %url_key = (
  "booktitle" => "bookurl",
  "series" => "seriesurl",
  "school" => "schoolurl",
  "institution" => "institutionurl",
  "conference" => "conferenceurl"
);

my %string_url_key = (
  "Technical report" => "techreporturl",
);

my %parts = (
    "booktitle" => sub { pad_part ($_[0], "<I>", "booktitle", "</I>") },
    "conference" => sub { return pad_part ($_[0], "<I>", "conference", "</I>") },
    "date" => sub {
        my ($month, $year) = (just_part ($_[0], "month"),
                              just_part ($_[0], "year"));
        if ($month =~ /^\w+\.?$/) {
            return $month . " " . $year;
        } elsif ($month) {
            return $month . ", " . $year;
        } else {
            return $year;
        }
    },
    "journal" => sub { pad_part ($_[0], "<I>", "journal", "</I>") },
    "number" => sub { pad_part ($_[0], "no. ", "number", "") },
    "pages" => sub {
      if (!($_[0]->{'pages'})) {
        return "";
      } elsif ($_[0]->{'pages'} =~ /^[-0-9]+$/) {
        return pad_part ($_[0], "pp. ", "pages", "");
      } else {
        return just_part ($_[0], "pages");
      }
    },
    "author" => \&author_list,
    "title" => sub { pad_part ($_[0], "``<A HREF=\"$_[0]->{'name'}\">",
                         "title", "</A>''") },
    "volume" => sub { pad_part ($_[0], "vol. ", "volume", "") }
);

################################## CODE ##################################

chdir "$ENV{HOME}/public_html/$kinds[0]->{'dir'}";
my ($bytype, $byname) = read_bibtex ("eddemaine.bib");

my $kind;
for $kind (0, 1) {
    chdir "$ENV{HOME}/public_html/$kinds[$kind]->{'dir'}";
    write_html ($kind);
}

system ("../bin/ctrs");

################################ ROUTINES ################################

sub read_bibtex {
    my ($filename) = @_;

    my ($type, $name, %entry);
    my $brace = "";
    my %bytype = ();
    my %byname = ();

    open BIBTEX, $filename or die "Couldn't open $filename for reading";

    while (<BIBTEX>) {
        chomp;
        if (/^\s*@/) {
            warn "$type $name wasn't finished (discarding)" if $brace;
            unless (/^\s*@(\w+)\s*([({])\s*(\w+)\s*,\s*$/) {
                warn "Bad bibentry format";
                next;
            }
            ($type, $brace, $name) = (lc $1, $2, $3);
            %entry = ("name" => $name, "type" => $type);
        } elsif ($brace) {
            if (/^\s*$complement{$brace}\s*$/) {
                warn "Unrecognized @-type $1 (ignoring)"
                    unless exists $at_types{$type};
                $bytype{$type} = [] unless exists $bytype{$type};
                $byname{$entry{'name'}} = { %entry };
                push @{$bytype{$type}}, $byname{$entry{'name'}};
                $brace = "";
            } else {
                if (/^\s*\w+\s*=\s*(\d+)/) {
                    substr ($_, length ($&) - length ($1), length ($1))
                        = '"' . $1 . '"';
                }
                if (/^\s*(\w+)\s*=\s*([{"])(.*)$/) {
                    my ($key, $val_brace, $val) = (lc $1, $2, $3);
                    my $endbrace = $complement{$val_brace};
                    my $start_line = $.;
                    until ($val =~ /${endbrace}(,?)$/) {
                        die "EOF while looking for $endbrace (starting at line $start_line)" unless defined ($_ = <BIBTEX>);
                        chomp;
                        $val .= $_;
                    }
                    warn "Missing comma after $type ${name}'s $key" unless $1;
                    $val =~ s/${endbrace}(,?)$//;
                    $entry{$key} = latex2html ($val);
                }
            }
        }
    }

    close BIBTEX;

    return (\%bytype, \%byname);
}

# Convert some of the LaTeX parts of a value to the corresponding HTML.
sub latex2html {
    my ($text) = @_;
    $text =~ s/\s\s+/ /g;
    $text =~ s#\\emph{([^{}]*)}#<I>$1</I>#g;
    $text =~ s/--/-/g;
    $text =~ s/{([^{}]*)}/$1/g;
    $text =~ s/\\'e/&eacute;/g;
    return $text;
}

################################ ROUTINES ################################

sub write_html {
    my ($kind) = @_;
    my ($this, $other) = ($kinds[$kind], $kinds[1-$kind]);

    open INDEX, ">$indexfile" or die "Couldn't open $indexfile for writing";
    select INDEX; html_head ("Erik Demaine's $this->{'name'}s");
    print INDEX "You may also be interested in Erik's ",
        "<A HREF=\"$base$other->{'dir'}/\">", lc ($other->{'name'}), "s</A>.\n";

    my $type;
    foreach $type (@{$this->{'order'}}) {
        next unless exists $bytype->{$type};
        my ($title, $actual_kind, $form, $comment) = @{$at_types{$type}};
        next unless $actual_kind == $kind;
        print INDEX "\n<H2> <A NAME=\"$type\">$title",
            (substr ($title, -1, 1) eq "s" ? "" : "s"), "</A> </H2>\n\n";
        print INDEX "$comment\n\n" if defined $comment;
        print INDEX "<UL>\n";

        my $e;
        foreach $e (@{$bytype->{$type}}) {
            my $text = use_form ($form, $e);
            print INDEX "<LI> " . $text . "\n";

            mkdir $e->{name}, 0755 unless -d $e->{name};
            chmod 0755, $e->{name};
            symlink "../../cgi-bin", "$e->{name}/cgi-bin"
                unless -l "$e->{name}/cgi-bin";
            touch ("$e->{name}/$ctrfile") unless -f "$e->{name}/$ctrfile";
            touch ("$e->{name}/$logfile") unless -f "$e->{name}/$logfile";
            if (open PAPER, ">$e->{name}/$indexfile") {
              select PAPER;
              if ($actual_kind == 1) { # Talk
                if (exists $e->{'presenter'}) {
                  html_head (author_list ($e) . ": $e->{'title'}",
                    $this->{'name'} . " by " . $e->{'presenter'});
                } else {
                  html_head (author_list ($e) . ": $e->{'title'}",
                    $this->{'name'} . " by " . (authors ($e)) [0]);
                }
              } else {
                html_head (author_list ($e) . ": $e->{'title'}",
                  $this->{'name'} . " by Erik D. Demaine");
                                        #. (authors ($e)) [0]);
              }
              print PAPER "<DL>\n";

              print PAPER "<DT><B>Reference</B>:</DT>\n";
              # Kill the first link
              $text =~ s#<A HREF=".*?">(.*?)</A>#$1#;
              print PAPER "<DD> $text </DD>\n";

              if (open ABSTRACT, "$e->{name}/$abstractfile") {
                print PAPER "<DT><B>Abstract</B>:</DT> <DD>\n";
                while (<ABSTRACT>) {
                  print PAPER $_;
                }
                close ABSTRACT;
              }

              if (exists $e->{'comments'}) {
                print PAPER "<DT><B>Comments</B>:</DT>\n";
                print PAPER "<DD> $e->{'comments'}\n";
              }

              if (exists $e->{'length'}) {
                print PAPER "<DT><B>Length</B>:</DT>\n";
                my @parts = split (/\s*;\s*/, $e->{'length'});
                print "<DD> The ", lc ($this->{'name'}), " is $parts[0]";
                print " and the ", lc ($other->{'name'}), " is $parts[1]"
                    if $#parts >= 1;
                print ".</DD>\n";
              }

              print PAPER "<DT><B>Availability</B>:\n";
              my $something = 0;
              my @which = ($this, $other);
              my $k;
              for $k (0, 1) {
                my @files = find_file ("$e->{name}/$which[$k]->{'file'}");
                print PAPER "<DD> The ", lc ($which[$k]->{'name'}),
                  " is", ($k > 0 ? " also" : ""),
                  " available in ", and_list (map {
                    "<A HREF=\"$which[$k]->{'file'}$_\">$suffixes{$_}</A>" .
                    file_size ("$e->{name}/$which[$k]->{'file'}$_")
                  } @files) . ".</DD>\n" if @files;
                $something = 1 if @files;
              }
              print PAPER "<DD> Currently unavailable.  ",
                "If you are in a rush for copies,\n",
                '<A HREF="mailto:eddemaine@uwaterloo.ca">contact me</A>',
                ".</DD>" unless $something;

              if (exists $e->{'software'}) {
                print PAPER "<DT><B>Software</B>:</DT>\n";
                my $project;
                foreach $project (split /\s*;\s*/, $e->{'software'}) {
                  print PAPER "<DD> <A HREF=\"$base$project\">$project",
                    "</A> </DD>\n";
                }
              }

              for $k (0, 1) {
                my $w = $kinds[$k];
                my $label = lc ($w->{'name'}) . "s";
                if (exists $e->{$label}) {
                  print PAPER "<DT><B>Related $label</B>:</DT>\n";
                  my $obj;
                  foreach $obj (split /\s*;\s*/, $e->{$label}) {
                    print PAPER "<DD> <A HREF=\"$base$w->{'dir'}/$obj",
                      "\">$obj</A>", (exists $byname->{$obj} ?
                      " ($byname->{$obj}->{'title'})" : ""),
                      " </DD>\n";
                  }
                }
              }


#               my @related = ();
#               push @related,
#                 "The corresponding <A HREF=\"$base$other->{'dir'}/$e->{name}\">"
#                 if exists $e->{"Has " . $type};
#               if (@related) {
#                 print PAPER "<DT><B>Related information</B>:\n";
#                 print PAPER "<DD><UL>\n<LI> ";
#                 print PAPER join ("\n<LI> ", @related);
#                 print PAPER "</UL>\n"
#               }

              print PAPER "</DL>\n<HR>\nSee also other ";
              print PAPER and_list (map {
                "<A HREF=\"$base$kinds[$_]->{'dir'}/\">" .
                lc ($kinds[$_]->{'name'}) . "s</A>";
              } (0,1));
              print PAPER " by <A HREF=\"$base\">Erik Demaine</A>.";
              html_foot ();
              close PAPER;
              chmod 0644, "$e->{name}/$indexfile";
            } else {
              warn "Couldn't write to $e->{name}/$indexfile";
            }
        }
        print INDEX "</UL>\n";
    }
    select INDEX; html_foot ();
    close INDEX;
    chmod 0644, $indexfile;
}

sub touch {
    my ($file) = @_;
    if (open TOUCHTEMP, ">>$file") {
        close TOUCHTEMP;
    } else {
        warn "Couldn't touch $file";
    }
}

sub html_head {
    my ($title, $head) = @_;
    $head = $title unless defined $head;
    print <<END;
<HTML>
<HEAD>
<TITLE> $title </TITLE>
</HEAD>
<BODY>
<H1> $head </H1>
END
}

sub html_foot {
    print <<END;

<HR>

<I>
These pages are generated automagically from a
<A HREF=\"${base}papers/eddemaine.bib\">BibTeX</A> file.
<BR>
<!--#config errmsg="[?]" -->
<!--#config timefmt="%B %e, %Y" -->
Last updated <!--#flastmod file="$indexfile" --> by
<A HREF="$base">Erik Demaine</A>.
You are the <!--#exec cgi="cgi-bin/ecounter.cgi" -->

</BODY>
</HTML>
END
}

sub find_file {
    my ($base) = @_;

    my $suffix;
    my @result = ();
    foreach $suffix (@suffix_order) {
        if (-r $base . $suffix) {
            push @result, $suffix;
            if (-d $base . $suffix) {
                chmod 0755, $base . $suffix;
            } else {
                chmod 0644, $base . $suffix;
            }
        }
    }

    return @result;
}

sub file_size {
  my ($filename) = @_;
  return "" if -d $filename;
  my @stats = (stat _);
  if ($#stats >= 7) {
    return " (" . int ($stats[7] / 1024) . "k)";
  }
}

sub and_list {
    my ($arg1, @rest1) = @_;
    if (@rest1) {
        my ($arg2, @rest2) = @rest1;
        if (@rest2) {
            return $arg1 . map {
                if ($_ == $#rest1) {
                    return ", and " . $rest1[$_];
                } else {
                    return ", " . $rest1[$_];
                }
            } @rest1;
        } else {
            return "$arg1 and $arg2";
        }
    } else {
        return $arg1;
    }
}

sub authors {
  my ($e) = @_;
  return split /\s*and\s*/, $e->{'author'};
}

sub author_list {
  my @list = authors (@_);
  if (scalar @list <= 0) {
    return "";
  } elsif (scalar @list == 1) {
    return $list[0];
  } elsif (scalar @list == 2) {
    return "$list[0] and $list[1]";
  } else {
    my $last = pop @list;
    return (join ", ", @list) . ", and $last";
  }
}

################################ ROUTINES ################################

sub use_form {
    my ($form, $entry) = @_;
    my ($text, $subtext, $punct, $nvar, $nnovar) = ("", "", "", 0, 0);

    while ($form =~ /(\w+)(\/\w+)?|[,. ]|"[^"]*"/) {
        my $c = substr ($&, 0, 1);
        if ($c eq "," || $c eq ".") {
            if ($nvar > 0 || $nnovar == 0) {
                if (length ($text) >= 2 &&
                        substr ($text, length ($text) - 2) eq "''") {
                    substr ($text, length ($text) - 2, 0) = $punct;
                } else {
                    $text .= $punct;
                }
                $text .= $subtext;
                $punct = $c;
            } else {
                $punct = $c unless $punct eq ".";
            }
            $subtext = "";
            $nvar = $nnovar = 0;
        } elsif ($c eq " ") {
            $subtext .= $c;
        } elsif ($c eq '"') {
          my $string = substr ($&, 1, -1);
          if (exists $string_url_key{$string}) {
            if (exists $entry->{$string_url_key{$string}}) {
              $string = "<A HREF=\"$entry->{$string_url_key{$string}}\">$string</A>";
            }
          }
          $subtext .= $string;
        } else {
          my ($var, $key);
          $key = $1;
          $key = substr ($2, 1) if defined $2 && !exists $entry->{$1};
          if (exists $parts{$key}) {
            $var = &{$parts{$key}} ($entry);
          } else {
            $var = just_part ($entry, $key);
          }
          if ($var) {
              $subtext .= $var;
              $nvar++;
          } else {
              $nnovar++;
          }
        }
        $form = substr ($form, length ($&));
    }

    return $text . $punct;
}

################################ ROUTINES ################################

sub just_part {
    my ($e, $key) = @_;

    if (exists $e->{$key}) {
        return make_link ($e, $key);
    } else {
        return "";
    }
}

sub pad_part {
    my ($e, $left, $key, $right) = @_;

    if (exists $e->{$key}) {
        return $left . make_link ($e, $key) . $right;
    } else {
        return "";
    }
}

sub make_link {
    my ($e, $key) = @_;
    my $val = $e->{$key};

    return $val unless exists $url_key{$key};

    my $url = $url_key{$key};
    if (exists $e->{$url}) {
        if ($val =~ /\(([^()]+)\)$/) {  # Put link around abbreviation
            $val = $` . "(<A HREF=\"$e->{$url}\">" . $1 . "</A>)";
        } else {                        # Put link around everything
            $val = "<A HREF=\"$e->{$url}\">$val</A>";
        }
    }

    return $val;
}

