#!/usr/bin/perl

use strict;
use warnings;

use File::Basename;

my %options;
my $dir;
my $parts;
my $formats;
my $file;

sub expandrw {
    my $read  = shift;
    my $write = shift;
    my $type  = shift;

    my $res = "";
    if ( ( $read eq 'r' ) || ( $write eq 'w' ) ) {
        $res .=
          "      <listitem>\n        <para role=\"fmtcapsitem\">\n          ";
        if ( ( $read eq 'r' ) && ( $write eq 'w' ) ) {
            $res .= "read and write $type";
        }
        elsif ( $read eq 'r' ) {
            $res .= "read $type";
        }
        elsif ( $write eq 'w' ) {
            $res .= "write $type";
        }
        $res .= "\n        </para>\n      </listitem>\n";
    }
    $res;
}

sub expandoptions {
    my $opts = shift;
    my $res =
"  <para role=\"fmtcapshdr\">\n    This format can...\n    <itemizedlist>\n";

    $res .=
      expandrw( substr( $opts, 0, 1 ), substr( $opts, 1, 1 ), 'waypoints' );
    $res .= expandrw( substr( $opts, 2, 1 ), substr( $opts, 3, 1 ), 'tracks' );
    $res .= expandrw( substr( $opts, 4, 1 ), substr( $opts, 5, 1 ), 'routes' );

    $res .= "    </itemizedlist></para>\n";

    $res;
}

sub expandsuboptions {
    my $f = shift;
    my $res;
    my $olist = $options{$f};

    # If no options, don't clutter things.
    if ( not defined($olist) ) { return; }

    # Comma separate the human-readable variation.
    $olist =~ s/> </>, </g;

    $res .= "<para>This format has the following options: ";
    $res .= $olist;
    $res .= ".</para>";

    $res;
}

sub include {
    my $name = shift;
    my $dir2 = shift;

    my $name2 = $name;
    $name2 =~ s/-/_/g;
    my $d2 = $dir2;
    $d2 =~ s:/.*::;
    $name2 = $d2 . '_' . $name2;

    #print $parts qq(<!ENTITY inc_$name2 SYSTEM "../$dir2/$name.xml">\n);
    #print $file "\&inc_$name2;\n";
    if ( !-e "$dir/$dir2/$name.xml" ) {
        open my $tmp, '>:encoding(UTF-8)', "$dir/$dir2/$name.xml" or die $!;
        print $tmp "\n";
        close $tmp;
    }
    open my $tmp2, '<:encoding(UTF-8)', "$dir/$dir2/$name.xml" or die $!;
    print $file qq(<!-- BEGIN inclusion of $dir/$dir2/$name.xml -->\n);
    while (<$tmp2>) {
        print $file $_;
    }
    print $file qq(<!-- END inclusion of $dir/$dir2/$name.xml -->\n);
    close $tmp2;
}

sub includef {
    my $name = shift;

    my $name2 = $name;
    $name2 =~ s/-/_/g;
    print $parts qq(<!ENTITY inc_$name2 SYSTEM "$name.xml">\n);
    print $formats "\&inc_$name2;\n";
}

$dir = dirname($0);

qx(mkdir -p $dir/autogen);
if ( $? != 0 ) {
    die "error creating autogen directory: $?";
}
open $parts, '>:encoding(UTF-8)', "$dir/autogen/_parts.xml" or die $!;
print $parts qq(<!-- This document is automatically generated. -->\n);
print $parts qq(<!ENTITY formats SYSTEM "_formats.xml">\n);
print $parts qq(<!ENTITY filters SYSTEM "_filters.xml">\n);

open $formats, '>:encoding(UTF-8)', "$dir/autogen/_formats.xml" or die $!;
print $formats qq(<!-- This document is automatically generated. -->\n);

my @formats = qx(./gpsbabel -^3);
if ( $? != 0 ) {
    die "error running gpsbabel: $?";
}

my $going     = 0;
my $dooptions = 0;

# Prescan the argument list for options.

my $fmt;
my $skipping;

for (@formats) {
    chomp;
    s/\&/\&amp;/g;
    s/</\&lt;/g;
    s/>/\&gt;/g;
    my @line = split "\t";
    next if ( scalar(@line) < 1 );

    if ( ( $line[0] eq 'file' ) || ( $line[0] eq 'serial' ) ) {
        $fmt = $line[2];

        # Pennance for earlier sins.  Rename magellan -> magellan1 here.
        if ( $line[4] eq "Magellan serial protocol" ) {
            $fmt = "magellan1";
        }
        $skipping = 0;
    }
    if (   ( $line[0] eq 'internal' )
        || ( defined( $line[5] ) && ( $line[5] eq 'xcsv' ) ) )
    {
        $skipping = 1;
    }
    if ( $line[0] eq 'option' && $skipping == 0 ) {
        my $optname = $line[2];

        $options{$fmt} .=
          "<link linkend=\"fmt_${fmt}_o_${optname}\">$optname</link> ";
    }
}

my $id;
my %fmts;

for (@formats) {
    chomp;
    s/\&/\&amp;/g;
    s/</\&lt;/g;
    s/>/\&gt;/g;
    my @line = split "\t";
    next if ( scalar(@line) < 1 );

    if ( $line[0] eq 'internal' ) {
        if ($going) {
            print $file "</section>\n";
            close $file;
            $going = 0;
        }
        if ( $line[5] eq 'xcsv' ) {
            $line[0] = 'file';
        }
    }

    if ( ( $line[0] eq 'file' ) || ( $line[0] eq 'serial' ) ) {
        if ($going) {
            print $file "</section>\n";
            close $file;
        }
        $id = $line[2];
        if ( $fmts{$id} ) {
            $id .= $fmts{$id}++;
        }
        else {
            $fmts{$id} = 1;
        }
        includef( 'fmt_' . $id );
        open $file, '>:encoding(UTF-8)', "$dir/autogen/fmt_$id.xml" or die $!;
        print $file <<END;
<!-- This document is automatically generated. -->
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="fmt_$id">
  <title>$line[4] ($line[2])</title>
END
        print $file expandoptions( $line[1] );
        print $file expandsuboptions($id);
        $going     = 1;
        $dooptions = 1;

        if ( defined( $line[5] ) && ( $line[5] ne $line[2] ) ) {
            print $file <<END;
<para>
This format is derived from the <link linkend="fmt_$line[5]">$line[5]</link>
format, so it has all of the same options as that format.
</para>
END
            if ( $line[5] eq 'xcsv' ) {
                $dooptions = 0;
            }
        }
        include( $id, "formats" );
    }
    elsif ( $going && $dooptions && ( $line[0] eq 'option' ) ) {
        my $nid = 'fmt_' . $id . '_o_' . $line[2];
        print $file <<END;
  <section xml:id="$nid">
    <title><option>$line[2]</option> option</title>
    <para>
      $line[3].
    </para>
END
        include( $id . '-' . $line[2], "formats/options" );
        print $file <<END;
  </section>
END
    }
}

if ($going) {
    print $file "</section>\n";
    close $file;
    $going = 0;
}

close $formats;
open $formats, '>:encoding(UTF-8)', "$dir/autogen/_filters.xml" or die $!;
print $formats qq(<!-- This document is automatically generated. -->\n);

my @filters = qx(./gpsbabel -%1);
if ( $? != 0 ) {
    die "error running gpsbabel: $?";
}

$going = 0;

for (@filters) {
    chomp;
    s/\&/\&amp;/g;
    s/</\&lt;/g;
    s/>/\&gt;/g;
    my @line = split "\t";

    if ( $going && ( $line[0] eq 'option' ) ) {
        print $file <<END;
  <section xml:id="flt_$line[1]_o_$line[2]">
    <title>$line[2] option</title>
    <para>
      $line[3].
    </para>
END
        include( $line[1] . '-' . $line[2], "filters/options" );
        print $file <<END;
  </section>
END
    }
    else {
        if ($going) {
            print $file "</section>\n";
            close $file;
        }
        includef( 'filter_' . $line[0] );
        open $file, '>:encoding(UTF-8)', "$dir/autogen/filter_$line[0].xml" or die $!;
        print $file <<END;
<!-- This document is automatically generated. -->
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="filter_$line[0]">
  <title>$line[1] ($line[0])</title>
END
        include( $line[0], "filters" );
        $going = $line[0];
    }
}

if ($going) {
    print $file "</section>\n";
    close $file;
    $going = 0;
}
close $formats;
close $parts;
