#!/usr/bin/perl
use strict;
#  Allow bare words, so &ade_err_error() calls look nicer.
no strict 'subs';
#  'use' is a compiler pragma, not a perl keyword; i.e.
#  it is executed at compile-time, not shortly after at
#  run-time. For this reason we need to put the 'use lib'
#  (which has to be before the 'require') and the require+import
#  (which is needed because we don't yet have a .pm file)
BEGIN {
#  This works, but it would be nicer to use a single
#  line with 'use' instead. But that will require that
#  either ade.pl calls the same thing, or that we
#  merge all those things into a single file. 
use lib substr `ade-config ade_include_prefix`,0,-1;
require "ade.pl";
ADE->import(qw($ade_app_progname ade_gep_main ade_tmp_registerfile ade_tmp_deregisterfile ade_err_error $ade_tmp_dir ade_msg_usage $ade_err_ok $ade_err_fail ade_err_registerdefderrs ade_msg_version ade_tmf_extractversionfromsvnstring ade_msg_listpaths ade_fcm_openwritecompressed ade_fcm_openreadcompressed));
use lib substr `fad-config fad_include_prefix`,0,-1;
require "fad.pl";
FAD->import(qw(fadstore_to_fadstream));
}

use Getopt::Long qw(:config no_ignore_case);
#  This won't be needed once FAD becomes a package
use Data::Dumper;

my($subversion_string) = '# $HeadURL$ $LastChangedRevision$';

&ade_err_registerdefderrs({
    fadcat_err_misc        => { fmt => "%s" },
});

my($opt_regexp, $opt_outfile);
my(@config_hasharray) = (
    { dsc => "opt_regexp",  var => \$opt_regexp,  dfl => "undefined" },
    { dsc => "opt_outfile", var => \$opt_outfile, dfl => "undefined" },
);
 
sub fadcat
{
    my($errstack_ref) = @_;
    #my($rc, $in_handle, $out_handle, %attribs, %names, %madeupdevinodes, $listpaths);
    my($rc, $in_handle, $out_handle, %data_store);

    #
    #  Load defaults, command line options and stuff from config file
    #

    if (($rc=&load_options_and_config_file($errstack_ref)) != $ade_err_ok) {
        return($rc);
    }
    &ade_err_debug($errstack_ref, 10, "mkfad: config loaded");

    ##########################################################################
    #
    #  Process arguments
    #
    ##########################################################################

    #  All arguments are optional.

    ##########################################################################
    #
    #  Guts
    #
    ##########################################################################


    if (defined($ARGV[0])) {
        while (defined($ARGV[0])) {
            $_ = shift @ARGV;
            &ade_err_debug($errstack_ref, 5, "fadcat: loading FAD stream to FAD store from $_ ...");
            if (($rc=&ade_fcm_openreadcompressed($errstack_ref, $_, \*IN_HANDLE)) != $ade_err_ok) {
                 &ade_err_error($errstack_ref, fadcat_err_misc, "can't open $_");
                 return($rc);
            }
            if (($rc=&fad_load($errstack_ref, \*IN_HANDLE, \%data_store, ($opt_regexp eq "undefined") ? undef : $opt_regexp)) != $ade_err_ok) {
                return($rc);
            }
            close IN_HANDLE;
        }
    } else {
        &ade_err_debug($errstack_ref, 5, "fadcat: loading FAD stream to FAD store from stdin ...");
        if (($rc=&fad_load($errstack_ref, \*STDIN, \%data_store, ($opt_regexp eq "undefined") ? undef : $opt_regexp)) != $ade_err_ok) {
            return($rc);
        }
    }

    &ade_err_debug($errstack_ref, 10, "fadcat: opt_outfile=$opt_outfile");
    if ($opt_outfile ne "undefined") {
        &ade_err_debug($errstack_ref, 10, "fadcat: opening output file ...");
        &ade_tmp_registerfile($errstack_ref, $opt_outfile);
        if (($rc=&ade_fcm_openwritecompressed($errstack_ref, $opt_outfile, \*OUT_HANDLE)) != $ade_err_ok) {
            &ade_err_error($errstack_ref, fadcat_err_misc, "can't open $opt_outfile");
            return($rc);
        }
        $out_handle = \*OUT_HANDLE;
    } else {
        $out_handle = \*STDOUT;
    }

    &ade_err_debug($errstack_ref, 10, "fadcat: dumping FAD store to " . (defined($opt_outfile) ? $opt_outfile : "stdout") .  " ...");
    if (($rc=&fad_dump($errstack_ref, $out_handle, \%data_store)) != $ade_err_ok) {
        return($rc);
    }

    if ($opt_outfile ne "undefined") {
        close OUT_HANDLE;
        &ade_tmp_deregisterfile($errstack_ref, $opt_outfile);
    }

    #  Ensure sensible return code
    return($ade_err_ok);
}

sub app_version
{
    my($errstack_ref, $version_ref) = @_;
    my($rc);

    if (($rc=&ade_tmf_extractversionfromsvnstring($errstack_ref, $subversion_string, $version_ref)) != $ade_err_ok) {
        &ade_err_internal($errstack_ref, "app_version: ade_tmf_extractversionfromsvnstring failed\n");
    }

    return($ade_err_ok);
}

sub app_listpaths
{
    my($errstack_ref, $pathlist_ref) = @_;
    my($rc);

    %$pathlist_ref = {};
    return($ade_err_ok);
}

sub app_usage
{
    print "Usage:   $ade_app_progname [ <options> ] [ <file> ...]\n";
    print "\n";
    #  standard options
    print "Options: -V | --version           display program version\n";
    print "         -v | --verbose           verbose\n";
    print "         -d | --debug=<level>     set debug level\n";
    print "         -h | --help              display this text\n";
    print "         -p | --list-paths        list used paths\n";
    #  application-specific option
    print "         -g | --grep=<regexp>     grep out lines containing <regexp>\n";
    print "         -o | --file=<outfile>    send output to <outfile> instead of stdout\n";
    print "\n";

    return($ade_err_ok);
}

sub load_options_and_config_file
{
    my($errstack_ref) = @_;
    my($key, $old_sigwarn_handler, $i);

    #
    #  Unset everything.
    #
    #  (This function needs to be re-entrant;it can be called when the
    #  program starts, but it can also be called when SIGHUP is recieved.)
    #

    for ($i=0; $i<=$#config_hasharray; $i++) {
        undef ${$config_hasharray[$i]{var}};
    }

    #
    #  Process command line options (top priority).
    #

    #  Redirect GetOptions's alerts to our alerter.
    $old_sigwarn_handler = $SIG{'__WARN__'};
    $SIG{'__WARN__'} = sub { &ade_msg_usage($errstack_ref, \&app_usage, 1); };
    Getopt::Long::GetOptions(
        #  Standard opts
        "V|version"       => sub { &ade_msg_version($errstack_ref, \&app_version); },
        "v|verbose"       => sub { $main::verboselevel = 3; },
        "d|debug=i"       => \$main::verboselevel,
        "h|help"          => sub { &ade_msg_usage($errstack_ref, \&app_usage, 0); },
        "p|list-paths"    => sub { &ade_msg_listpaths($errstack_ref, \&app_listpaths); },
        #  Application specific opts
        "g|grep=s"        => \$opt_regexp,
        "o|file=s"        => \$opt_outfile,
    );
    $SIG{'__WARN__'} = $old_sigwarn_handler;

    #
    #  Assign defaults (third priority therefore done third)
    #

    for ($i=0; $i<=$#config_hasharray; $i++) {
        #  Skip using default if variable already has value
        next if (defined(${$config_hasharray[$i]{var}}));
        #  Skip using default if there is no default!
        next if (!defined($config_hasharray[$i]{dfl}));
        #  Use default
        ${$config_hasharray[$i]{var}} = $config_hasharray[$i]{dfl};
    }

    #
    #  Derivations
    #
    #  Some values depend on others. Work those out now.
    #

    #
    #  Verify that everything is now set.
    #

    for ($i=0; $i<=$#config_hasharray; $i++) {
        next if (defined(${$config_hasharray[$i]{var}}));
        &ade_err_error($errstack_ref, ade_err_undefined, $config_hasharray[$i]{dsc});
        return($ade_err_fail);
    }

    #
    #  Miscellaneous sanity checks
    #

    #
    #  If we get this far everything is ok.
    #

    return($ade_err_ok);
}


&ade_gep_main(\&fadcat);
