#!/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]);
}
