#!/usr/bin/perl
#use strict;
#  '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 ));
use lib substr `INCLUDEPREFIX=../include fad-config includeprefix`,0,-1;
require "fad.pl";
FAD->import(qw(fadstore_to_fadstream));
}

use Getopt::Long;

$subversion_string = '# $HeadURL$ $LastChangedRevision$';

my(%defined_errors) = (
    ade_err_misc        => { fmt => "%s" },
);

my(@config_hasharray) = (
    { var => \$opt_outfile },
    { var => \$opt_infile },
    { var => \$opt_nocrcs, dfl => 0 },
);
 
#  Other globals
#  Extra perl library directories
#  Are there any directories where other libraries are to be found? Just use
#  a colon separated list of directories.
my($extra_perllib_dirs) = "SPPSYM_EXTRAPERLLIBDIRS";
#  Important bits
push(@INC,split(/[:\s]+/,$extra_perllib_dirs));

sub mkfad
{
    my($errstack_ref) = @_;
    my($rc, $in_handle, $out_handle);
    my(%attribs, %names, %madeupdevinodes);	# FAD store
    my($listpaths, $optval, $packed_fadrec, $collected_info_array_ref);

    printf "mkfad: sof\n";

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

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

    $rc = 0;
    #  Open file list if specified
    if (defined($opt_infile)) {
        if (($rc=&ade_fcm_openreadcompressed($errstack_ref, $opt_infile, \*IN_HANDLE)) != $ade_err_ok) {
            &ade_err_error($errstack_ref, $defined_errors{ade_err_misc}, "can't open $opt_infile");
            return($rc);
        }
        $in_handle = \*IN_HANDLE;
    } else {
        $in_handle = \*STDIN;
    }

    #  Slurp file list, generate FAD records, and store in internal store
    while (<$in_handle>) {
        chomp;
        #  0 means don't suppress the calculation of files' CRCs
        &ade_err_debug($errstack_ref, 10, "mkfad: $_: collecting info ...");
        if (($rc=&collect_info($errstack_ref, $_, $opt_nocrcs, \$collected_info_array_ref)) != $ade_err_ok) {
            return($rc);
        }
        &ade_err_debug($errstack_ref, 10, "mkfad: $_: collected info: " . join(', ', @{$collected_info_array_ref}));
        &ade_err_debug($errstack_ref, 10, "mkfad: $_: packing into a record ...");
        if (($rc=&pack_fadrec($errstack_ref, $collected_info_array_ref, \$packed_fadrec, \%attribs, \%names, \%madeupdevinodes)) != $ade_err_ok) {
            return($rc);
        }
        &ade_err_debug($errstack_ref, 10, "mkfad: $_: storing record ...");
        if (($rc=&insert_fadrecord_in_fadstore($errstack_ref, $packed_fadrec, \%attribs, \%names, \%madeupdevinodes)) != $ade_err_ok) {
            return($rc);
        }
        &ade_err_debug($errstack_ref, 10, "mkfad: $_: done");
    }

    #  Close input file if necessary
    defined($opt_infile) && close IN_HANDLE;
 
    #  Open output file if specified
    if (defined($opt_outfile)) {
        &ade_err_debug($errstack_ref, 10, "mkfad: regisering outfile $opt_outfile ...");
        &ade_tmp_register($errstack_ref, $opt_outfile);
        if (($rc=&ade_fcm_openwritecompressed($errstack_ref, $opt_outfile, \*OUT_HANDLE)) != $ade_err_ok) {
            &ade_err_error($errstack_ref, $defined_errors{ade_err_misc}, "can't open $opt_outfile");
            return($rc);
        }
        $out_handle = \*OUT_HANDLE;
    } else {
        &ade_err_debug($errstack_ref, 10, "mkfad: outfile is stdout");
        $out_handle = \*STDOUT;
    }

    #  Print all records to the output handle.
    &ade_err_debug($errstack_ref, 10, "mkfad: dumping records to outfile ...");
    if (($rc=&fadstore_to_fadstream($errstack_ref, $out_handle, \%attribs, \%names, \%madeupdevinodes)) != $ade_err_ok) {
        return($ade_err_ok);
    }

    #  Close output file if necessary
    if (defined($opt_outfile)) {
        close OUT_HANDLE;
        &ade_tmp_deregister($opt_outfile);
    }

    #  Now that we have finished with the FAD store, we can clear it of all records.
    undef %attribs;
    undef %names;
    undef %madeupdevinodes;

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

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

    ${$version_ref} = $main::version;

    return($ade_err_ok);
}

sub app_usage
{
    print "Usage:   $ade_app_progname [ <options> ]\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 "         -n | --suppress-crcs     suppress collecting file content checksums\n";
    print "         -i | --infile=<infile>   read file list from <infile> instead of stdin\n";
    print "         -o | --outfile=<outfile> send output to <outfile> instead of stdout\n";
    print "\n";

    return($ade_err_ok);
}

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

    #  If there is only one log file use this
    #print "Log-File: $main::log_file\n"

    #  If there are several, then just report the directory
    #print "Log-Directory: $main::log_dir\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); },
        #  Application specific opts
        "n|suppress-crcs" => \$opt_nocrcs,
        "i|infile=s"      => \$opt_infile,
        "o|outfile=s"     => \$opt_outfile,
    );
    $SIG{'__WARN__'} = $old_sigwarn_handler;

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

    print "load_options_and_config_file: about to assign defaults ...\n";
    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.
    #
    #  Note that the order in which they are worked out is important
    #  (e.g. mail_log_dir needs to be determined *before* mail_log_file
    #  because if the second is not absolute then the first is used as
    #  a prefix). Hence the 'sort' and 'if (key is ...) elsif (key is ..)'
    #

    print "load_options_and_config_file: derivations ...\n";
#    foreach $key (sort { if (!defined($a{pri})) { return(1); } elsif (!defined($b{pri})) { return(-1); } else { return ($a{pri} <=> $b{pri}); }} @config_hasharray) {
#        &ade_err_debug($errstack_ref, 10, "load_options_and_config_file: key: $key");
#        if ($key =~ /mail_retr_port/ && !defined(${$confighash_map{$key}{var}})) {
#            ${$confighash_map{$key}{var}} = (${$confighash_map{mail_retr_method}{var}} eq "IMAP")
#? 143 : 110;
#        } elsif ($key =~ /mail_retr_(username|password)/ && !defined(${$confighash_map{$key}{var}}) && ${$confighash_map{mail_retr_authenticate}{var}} eq "NONE") {
#            #  Put dummy text in so that the 'is everything set?' test below passes.
#            ${$confighash_map{$key}{var}} = "unused";
#        } elsif ($key =~ /mail_send_(username|password)/ && !defined(${$confighash_map{$key}{var}}) && ${$confighash_map{mail_send_authenticate}{var}} eq "NONE") {
#            #  Put dummy text in so that the 'is everything set?' test below passes.
#            ${$confighash_map{$key}{var}} = "unused";
#        } elsif ($key =~ /mail_.*_dir/) {
#            #  If a directtory specification is not absolute, make it so.
#            ${$confighash_map{$key}{var}} =~ s/^(?!\/)/getcwd."\/"/e;
#        } elsif ($key =~ /mail_lock_file/) {
#            #  If lock file not absolute, make it so.
#            ${$confighash_map{$key}{var}} =~ s/^(?!\/)/$lock_dir\//;
#        } elsif ($key =~ /mail_log_file/) {
#            #  If log file not absolute, make it so.
#            ${$confighash_map{$key}{var}} =~ s/^(?!\/)/$log_dir\//;
#        } elsif ($key =~ /mail_(retr|send)_mbox_file/) {
#            #  If log file not absolute, make it so.
#            ${$confighash_map{$key}{var}} =~ s/^(?!\/)/$log_dir\//;
#        } elsif ($key =~ /mail_(status|stats_archive)_table/) {
#            #  If status table not absolute, make it so.
#            ${$confighash_map{$key}{var}} =~ s/^(?!\/)/$state_dir\//;
#        }
#    }

    #
    #  Verify that everything is now set.
    #

    print "load_options_and_config_file: checking all set ...\n";
    for ($i=0; $i<=$#config_hasharray; $i++) {
        next if (defined(${$config_hasharray[$i]{var}}));
        &ade_err_error($errstack_ref, $defined_errors{ade_err_undefined}, $config_hasharray[$i]{var});
        return($ade_err_fail);
    }

    #
    #  Miscellaneous sanity checks
    #

#    if (!$retr_interval && !$send_interval && !$stat_interval) {
#        &ade_err_error($errstack_ref, $defined_errors{ade_err_config}, "retrieve, send and stat intervals are all zero!");
#        return($ade_err_fail);
#    }

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

    print "load_options_and_config_file: returning ...\n";
    return($ade_err_ok);
}


&ade_gep_main(\&mkfad);
