#!/usr/bin/perl
#
# Generate the txt2man source for topcom.7 from the upstream manual.
#
# The "Commands" and "Command Line Options" sections of
# doc/TOPCOM-manual.tex are extracted and rewritten into the simple
# two-column layout that txt2man consumes.  This keeps the manual the
# single source of truth for the manpage.  Run from debian/rules on the
# patched source; the result is fed to txt2man.
#
# Usage: perl debian/manual2txt.pl doc/TOPCOM-manual.tex > debian/topcom.txt

use strict;
use warnings;

local $/;
my $tex = <>;

# --- pull out the two sections we care about -------------------------------
sub section_body {
    my ($title) = @_;
    return $tex =~ /\\section\{\Q$title\E\}(.*?)(?=\\section\{)/s ? $1 : '';
}
my $cmds = section_body('Commands');
my $opts = section_body('Command Line Options');

# --- LaTeX -> plain text ---------------------------------------------------
sub strip {
    my ($s) = @_;
    $s =~ s/\\texttt\{((?:[^{}]|\{[^{}]*\})*)\}/$1/g;
    $s =~ s/\\emph\{([^{}]*)\}/$1/g;
    $s =~ s/\\url\{([^{}]*)\}/$1/g;
    $s =~ s/\\LaTeX\b/LaTeX/g;
    $s =~ s/\\ldots/.../g;
    $s =~ s/\\times/x/g;
    $s =~ s/\\ell/l/g;
    $s =~ s/\\choose/choose/g;
    $s =~ s/\\_/_/g;
    $s =~ s/``/"/g;            # LaTeX open quotes
    $s =~ s/''/"/g;            # LaTeX close quotes
    $s =~ s/\$//g;             # drop math delimiters
    $s =~ s/[{}]//g;           # drop leftover braces from math groups
    $s =~ s/~/ /g;             # non-breaking space
    $s =~ s/\\ / /g;           # "\ " (e.g. Dto.\ )
    $s =~ s/\\\\/ /g;          # explicit line breaks
    # drop upstream editorial markers, keep meaningful parentheticals
    $s =~ s/\(New;\s*currently the default\.\)/(Currently the default.)/gi;
    $s =~ s/\(New;\s*([^)]*)\)/($1)/g;
    $s =~ s/\(New form\.\)\s*//g;
    $s =~ s/\(New\.\)\s*//g;
    # neutralise the (n)/(co) client shorthand that crashes txt2man's regex
    $s =~ s/\(n\)/[n]/g;
    $s =~ s/\(co\)/[co]/g;
    $s =~ s/\(co-\)/[co-]/g;
    $s =~ s/\s+/ /g;
    $s =~ s/^\s+|\s+$//g;
    $s =~ s/:$//;              # trailing colon on labels/headers
    return $s;
}

# --- word-wrap into the txt2man two-column layout --------------------------
my $COL   = 26;    # description column / continuation indent
my $WIDTH = 78;

sub wrap {
    my ($first, $rest, @words) = @_;    # first-line prefix, continuation indent
    my @lines;
    my $cur = $first;
    for my $w (@words) {
        if ($cur =~ /\S/ && length($cur) > length($rest)
                && length($cur) + 1 + length($w) > $WIDTH) {
            push @lines, $cur;
            $cur = $rest . $w;
        } else {
            $cur .= ($cur =~ /\S$/ ? ' ' : '') . $w;
        }
    }
    push @lines, $cur if $cur =~ /\S/;
    return join "\n", @lines;
}

sub emit_item {
    my ($name, $desc) = @_;
    my $lead = '  ' . $name;
    my $first = length($lead) + 2 <= $COL
        ? $lead . (' ' x ($COL - length($lead)))
        : $lead . '  ';
    return wrap($first, ' ' x $COL, split ' ', $desc);
}
sub emit_para { return wrap('  ', '  ', split ' ', $_[0]); }

# --- walk a section body into events (head / item / para) ------------------
sub events {
    my ($body) = @_;
    # sentinel-mark item labels (labels may contain one level of [...], e.g. $[\ell]$)
    $body =~ s/\\item\[((?:[^\[\]]|\[[^\[\]]*\])*)\]/\n\x01$1\x02/g;
    $body =~ s/\\subsection\*\{([^{}]*)\}/\n\x03$1\x03\n/gs;
    $body =~ s/\\(?:begin|end)\{description\}//g;
    $body =~ s/\\label\{[^{}]*\}//g;
    my @ev;
    while ($body =~ /\G(?:\x03(.*?)\x03|\x01(.*?)\x02(.*?)(?=\x01|\x03|$)|(.+?)(?=\x01|\x03|$))/sgc) {
        if    (defined $1) { push @ev, ['head', strip($1)]; }
        elsif (defined $2) { push @ev, ['item', strip($2), strip($3)]; }
        else               { my $p = strip($4); push @ev, ['para', $p] if $p ne ''; }
    }
    return @ev;
}

# --- assemble the output ---------------------------------------------------
my @out = (
    'NAME',
    '  TOPCOM - Triangulations Of Point Configurations and Oriented Matroids',
    'COMMANDS',
    '  The following commands are provided. In Debian, each command is prefixed by',
    '  "topcom-".',
    '',
);
for my $e (events($cmds)) {
    push @out, emit_item($e->[1], $e->[2]) if $e->[0] eq 'item';
}

push @out, 'OPTIONS';
for my $e (events($opts)) {
    if    ($e->[0] eq 'head') { push @out, '', '  ' . uc($e->[1]), ''; }
    elsif ($e->[0] eq 'para') { push @out, emit_para($e->[1]); }
    else                      { push @out, emit_item($e->[1], $e->[2]); }
}

push @out, '',
    'AUTHOR',
    "  This manpage was adapted from sections 4 and 5 of the TOPCOM Manual by J\x{f6}rg",
    '  Rambau.',
    '  See https://www.wm.uni-bayreuth.de/de/team/rambau_joerg/TOPCOM-Manual/.';

binmode STDOUT, ':utf8';
print join("\n", @out), "\n";
