#!/usr/bin/perl -w
#-------------------------------------------------------------------------------
# footnote.pl                                    (C) 2008 T.Birnthaler OSTC GmbH
# $Id: footnote.pl,v 1.6 2008/09/03 14:58:34 tsbirn Exp tsbirn $
#-------------------------------------------------------------------------------
# Numerierte Fussnoten-Verweise der Form "[N]" eines beliebig langen Textes
# in der Reihenfolge des Vorkommens im Text neu von 1..n durchnummerieren.
# Die Zeilen der Form "[N] TEXT" mit neuer Fussnotennummer + Fussnotentext nach
# dem Schlüsselwort "@footnote:" aufsteigend sortiert ausgeben.
#
# Folgende Fehler werden erkannt:
# 1) Zu Verweisnummer im Text gibt es keine Nummer in Fussnotenliste.
# 2) Nummer in Fussnotenliste kommt mehrfach vor.
# 3) Zu Nummer in Fussnotenliste gibt es keine Verweisnummer im Text
#    (überflüssiger Fussnoteneintrag).
# 4) Fussnoteneintrag nicht in Form "[N] TEXT" (ungültig)
#-------------------------------------------------------------------------------
# Beispiel:
#   Text mit Verweis [123]
#   Text [5] mit Verweis [1]
#   ...
#   Text mit Verweis [123]
#   Text [5] mit Verweis [1]
#   @footnote:
#   [123] Dies ist der Fussnotentext 1
#   [1] Dies ist der Fussnotentext 2
#   [5] Dies ist der Fussnotentext 3
#-------------------------------------------------------------------------------
use strict;

my $dbg           = 0;
my %footnote_map  = ();
my $textline_cnt  = 0;
my @footnote_text = ();
my $new_nr        = 0;

#-------------------------------------------------------------------------------
# Text zeilenweise einlesen, jede Zeile SOFORT mit aufsteigenden numerierten
# Fussnotennummern wieder ausgeben
#-------------------------------------------------------------------------------
print STDERR "READING TEXT..." if ($dbg);

while (<>)
{
       last if (/^\@footnote:$/);
       ++$textline_cnt;
       print STDERR "TEXT: $_" if ($dbg);

       # Alle neuen Verweise in Zeile mit aufsteig. Nummer neu numeriert merken
       while (/\[(\d+)\]/g)
       {
               $footnote_map{$1} = ++$new_nr if (not defined($footnote_map{$1}));
               print STDERR "MAP: $1 => $footnote_map{$1}\n" if ($dbg);
       }

       # Alle Verweise in Zeile durch passende aufsteig. nummerierte ersetzen
       s/\[(\d+)\]/[$footnote_map{$1}]/g;

       print $_;
}

# Trennzeile "@footnote:" ausgeben
print $_;

print STDERR "TEXT LINES: $textline_cnt\n" if ($dbg);
print STDERR "SEPLINE: $_\n" if ($dbg);
print STDERR "NEW: $new_nr new footnote numbers\n" if ($dbg);

#-------------------------------------------------------------------------------
# Fussnoten einlesen, alte Nummer in neue konvertieren und merken.
#-------------------------------------------------------------------------------
print STDERR "READING FOOTNOTES..." if ($dbg);

while (<>)
{
       print STDERR "FOOT: $_" if ($dbg);

       # Zeilen nicht im Format "[N] TEXT" überspringen
       # ERROR 4: Fussnoteneintrag nicht in Form "[N] TEXT" (ungültig)
       if (not /^\[(\d+)\]\s+\S/)
       {
               warn("ERR(4): footnote entry wrong format '$_'\n");
               next;
       }

       # Zeile mit Format "[N] TEXT" zerlegen in N + TEXT
       my ($nr, $text) = /^\[(\d+)\]\s+(.*)/s;
       # ERROR 3: Zu Nummer in Fussnotenliste gibt es keine Verweisnummer im Text
       #          (überflüssiger Fussnoteneintrag).
       if (not defined $footnote_map{$nr}) {
               warn("ERR(3): [$nr] not used in text\n");
               next;
       }
       # ERROR 2: Nummer in Fussnotenliste kommt mehrfach vor.
       elsif (defined $footnote_text[$footnote_map{$nr}]) {
               warn("ERR(2): [$nr] used more than once in footnote list\n");
       }

       # Text zu neuer Fussnotennummer merken
       $footnote_text[$footnote_map{$nr}] = $text;
}
print STDERR "FOOT: ", scalar @footnote_text - 1, " footnotes found\n" if ($dbg);

#-------------------------------------------------------------------------------
# Fussnoten aufsteigend sortiert nach Nummer ausgeben
#-------------------------------------------------------------------------------
foreach my $nr (1 .. scalar @footnote_text)
{
       print "[", $nr, "] ", $footnote_text[$nr]
               if (defined $footnote_text[$nr]);
}

# ERROR 1: Zu Verweisnummer im Text gibt es keine Nummer in Fussnotenliste.
while (my ($old_nr, $new_nr) = each %footnote_map)
{
       warn("ERR(1): missing [$old_nr] in footnote list\n")
               if (not defined $footnote_text[$new_nr]);
}