#!/usr/bin/perl

sub usage {
    print STDERR "$_[0]\n\n" if length($_[0]);
    print STDERR 
"Usage: saspconvert <tocstyle> <footnotes> [<inputfile> ...]
 <tocstyle> may be:
   \`opt'  - the TOC is optional
   \`size' - if the TOC is absent then pretend TOC DETAIL=CHAPT
   \`none' - do no processing of the TOC (but still add attribs to sections)
 <footnotes> may be
   one of the element names \`P' \`CHAPT' \`BOOK' - footnotes are replaced
           with FOOTNOTEREF elements, and FOOTNOTEBODY is delayed until
           a FOOTNOTES element inserted just before the end of the element type
           specified
   one of those element names, but with a \`+' appended - footnotes are
           delayed as before, but inserted just _after_ the element end
   \`.' - no processing of footnotes is done
";
    exit(3);
}

$tocstyle= shift(@ARGV);
$footnotes= shift(@ARGV);

$tocstyle eq 'opt' || $tocstyle eq 'size' || $tocstyle eq 'none' ||
    &usage("toc style \`$tocstyle' be \`opt', \`size' or \`none'");
$footnotes= uc $footnotes;
$footnotesafter= ($footnotes ne '.+' && $footnotes =~ s/\+$//);
$footnotes eq 'P' || $footnotes eq 'CHAPT' || $footnotes eq 'BOOK' ||
    $footnotes eq '.' ||
    &usage("footnotes \`$footnotes' must be \`P', \`CHAPT', \`BOOK' or \`.'");

@data= <>;
$toclocation= -1;
$titlepaglocation= -1;
&initfootnotes;
$cifile='';
$ciline=0;

for ($i=0;$i<=$#data;$i++) {
    $_= $data[$i]; $footchange=0;
    if (m/^L(\d+)$/) {
        $ciline= $1;
        $cilinefile= "L$ciline $cifile\n" if defined($cifile);
    } elsif (m/^L(\d+) (.*)\n$/) {
        $ciline= $1;
        $cifile= $2;
        $cilinefile= $_;
    }
    $srclinefile[$i]= "$cifile:$ciline" if defined($ciline);
    if (m/^A(\S+) (.*)\n$/) {
        $attribcollect{$1}= $2;
    } elsif (m/^\(/) {
        %attrib= %attribcollect;
        undef %attribcollect;
    }
    if (m/^\(CHAPT$/) {
        $level= 'CHAPT';
        $num{'CHAPT'}++;
        $num{'SECT0'}= 0;
        $sectionstring='';
        &getid('ch');
        $chaptsysrefid= $sysrefid;
        $chaptsectattribs= ("ASRID CDATA $sysrefid\n".
                            "ACHAPT CDATA $num{'CHAPT'}\n".
                            "ASECT IMPLIED\n".
                            "AHNAME CDATA chapter $num{'CHAPT'}\n");
        $insert[$i].= $chaptsectattribs;
    } elsif (m/^\((SECT(\d*))$/) {
        $level= $1; $sl= $2+0;
        $num{"SECT$sl"}++;
        $num{"SECT".($sl+1)}= 0;
        $sectionstring='';
        grep($sectionstring.='.'.$num{"SECT$_"}, 0..$sl);
        &getid('s');
        $chaptsectattribs= ("ASRID CDATA $sysrefid\n".
                            "ACHAPT CDATA $num{'CHAPT'}\n".
                            "ACSRID CDATA $chaptsysrefid\n".
                            "ASECT CDATA $sectionstring\n".
                            "AHNAME CDATA ".
                            ($sl<3 ? ('sub'x$sl).'section' :
                             'sub'x($sl-3).'paragraph').
                            " $num{'CHAPT'}$sectionstring\n");
        $insert[$i].= $chaptsectattribs;
    } elsif (m/^\(HEADING$/) {
        $thisheadattribs= ("ALEVEL CDATA $level\n".
                           $chaptsectattribs);
        $thisheaddata= $cilinefile;
        $inheading=1;
        next;
    } elsif (m/^\)HEADING$/) {
        $tocdata.= ($thisheadattribs.
                    "(TOCENTRY\n".
                    $thisheaddata.
                    ")TOCENTRY\n");
        if (length($userrefid)) {
            $urid2attribs{$userrefid}= $thisheadattribs;
            $urid2data{$userrefid}= $thisheaddata;
        }
        $inheading= 0;
    } elsif (m/^\(TOC$/ && $tocstyle ne 'none') {
        $toclocation= $i;
    } elsif (m/^\)TOC$/ && $tocstyle ne 'none') {
        $append[$i].= $cilinefile;
    } elsif (m/^\)TITLEPAG$/ && $tocstyle ne 'none') {
        $append[$i].= $cilinefile;
        $titlepaglocation= $i;
    } elsif (m/^\(REF$/) {
        $attrib{'ID'} =~ m/^CDATA / || &error($i,"no CDATA for ID REF");
        $refline2urid{$i}= $';
    } elsif (m/^\(QREF$/) {
        $attrib{'ID'} =~ m/^CDATA / || &error($i,"no CDATA for ID REF");
        $qrefline2urid{$i}= $';
    } elsif (m/^\(FOOTNOTE$/ && $footnotes ne '.') {
        push(@footstack,$currentfootnum);
        $currentfootnum= ++$lastfootnum;
        $data[$i]= ("ANUMBER CDATA $currentfootnum\n".
                    "(FOOTNOTEREF\n");
        $footdata[$currentfootnum]= ($cilinefile.
                                     "ANUMBER CDATA $currentfootnum\n");
        $footdata[$currentfootnum].= ("ACHAPT CDATA $num{'CHAPT'}\n".
                                      "ACSRID CDATA $chaptsysrefid\n")
            if $footnotes eq 'BOOK';
        $footdata[$currentfootnum].= "(FOOTNOTEBODY\n";
        $footchange= 1;
    } elsif ($currentfootnum && m/^\)FOOTNOTE$/) {
        $footdata[$currentfootnum].= ")FOOTNOTEBODY\n";
        $currentfootnum= pop(@footstack);
        $data[$i]= ")FOOTNOTEREF\n".$cilinefile;
        $footchange= -1;
    }
    if ($addtofootnum= $footchange>0 ? $footstack[$#footstack] : $currentfootnum) {
        $footdata[$addtofootnum].= $data[$i];
        $data[$i]= '';
    } elsif ($lastfootnum && m/\)(\w+)$/ && $1 eq $footnotes) {
        $footdata= "(FOOTNOTES\n";
        for ($j=1;$j<=$lastfootnum;$j++) { $footdata.= $footdata[$j]; }
        $footdata.= ")FOOTNOTES\n".$cilinefile;
        if ($footnotesafter) { $append[$i].= $footdata; }
        else { $insert[$i].= $footdata; }
        &initfootnotes;
    } elsif ($inheading && !$footchange) {
        $thisheaddata.= $data[$i];
    }
}

for $i (keys %refline2urid) {
    $userrefid= $refline2urid{$i};
    defined($urid2attribs{$userrefid}) ||
        &error("identifier \`$userrefid' is undefined",$i);
    $insert[$i].= $urid2attribs{$userrefid};
    $append[$i].= $urid2data{$userrefid};
}

for $i (keys %qrefline2urid) {
    $userrefid= $qrefline2urid{$i};
    defined($urid2attribs{$userrefid}) ||
        &error("identifier \`$userrefid' is undefined",$i);
    $insert[$i].= $urid2attribs{$userrefid};
}

if ($lastfootnum) {
    die "leftover footnotes $lastfootnum";
}

if ($toclocation >= 0) {
    $append[$toclocation].= $tocdata;
} elsif ($tocstyle eq 'size' && $titlepaglocation >= 0) {
    $append[$titlepaglocation].= ("ADETAIL TOKEN CHAPT\n".
                                  "(TOC\n".
                                  $tocdata.
                                  ")TOC\n");
}

for ($i=0;$i<=$#data;$i++) { print($insert[$i],$data[$i],$append[$i]) || die $!; }
close(STDOUT) || die $!;

exit($errors ? 1 : 0);

sub getid {
    if ($attrib{'ID'} =~ m/^CDATA /) {
        $userrefid= $';
        $sysrefid= $_[0].'-'.$userrefid;
        if (defined($defpos{$userrefid})) {
            &error("indentifier $userrefid is defined more than once",$i);
            &error("indentifier $userrefid originally defined here",$defpos{$userrefid})
                if length($defpos{$userrefid});
            $defpos{$userrefid}= '';
        } else {
            $defpos{$userrefid}= $i;
        }
    } else {
        $userrefid= '';
        $sysrefid= $_[0].$num{'CHAPT'}.$sectionstring;
    }
}

sub error {
    my ($m,$l)=@_;
    my $emsg= "saspconvert: ";
    $emsg.= "$srclinefile[$l] " if length($srclinefile[$l]);
    $emsg.= "(input line $l): $m";
    print(STDERR "$emsg\n") || die $!;
    $errors++;
    if ($errors >=20) {
        print(STDERR "saspconvert: too many errors, stopping\n");
        exit(2);
    }
}

sub initfootnotes {
    @footnum=();
    @footdata=();
    @footstack=();
    $lastfootnum=0;
    $currentfootnum=0;
}
