#!SPPSYM_PERL_CMD
#spp comment vim: set filetype=perl: #
#spp include ../bldcfg/paths.spp
use strict; 
#  leave a standard path unless there is some reason not to
$ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin';
($main::progname = $0) =~ s/^.*\/([^\/]+)/$1/;
$main::svn_id = '$HeadURL$ $LastChangedRevision$';
$main::version_scheme = 'release';
$main::release_version = 'SPPSYM_RELEASE_ID';
my($tmp_dir) = ($ENV{'TMPDIR'}) ? $ENV{'TMPDIR'} : "SPPSYM_TMPDIR";

#  Defaults for options
my($dflt_outfile) = "-";
my($dflt_ignowner) = 0;
my($dflt_igngroup) = 0;
my($dflt_ignperms) = 0;

#  Option variables (needed at global level 'cos used in path reporting function)
undef my($opt_outfile);
undef my($opt_ignowner);
undef my($opt_igngroup);
undef my($opt_ignperms);

#  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 main
{
    my(@ARGV) = @_;
    my($fad1_file, $fad2_file, $out_handle, $fad1_handle, $fad2_handle);
    my($rc, $diff_rc, $listpaths, $optval);

    ##########################################################################
    #
    #  PROCESS OPTIONS
    #
    ##########################################################################

    #
    #  Load option values from command line
    #
    while (defined($ARGV[0]) && $ARGV[0] =~ /^-./) {
        $_ = $ARGV[0];

        #  standard options
        if (/^(?:-V|--version)$/) {
            &ade_msg_version(\&app_version);

        } elsif (/^(-d$|--debug=)(.*)/) {
            $main::verboselevel = ($1 !~ /^-[^-]/) ? $2 : ((defined($ARGV[1])) ? scalar($optval=$ARGV[1],shift @ARGV,$optval) : &ade_msg_usage(\&app_usage, 1));

        } elsif (/^(?:-v|--verbose)$/) {
            $main::verboselevel = 3;

        } elsif (/^(?:-h|--help)$/) {
            &ade_msg_usage(\&app_usage, 0);

        } elsif (/^(?:-p|--list-paths)$/) {
            $listpaths = 1;

        } elsif (/^(-g$|--ignore-gid$)/) {
            $opt_igngroup = 1;

        } elsif (/^(-u$|--ignore-uid$)/) {
            $opt_ignowner = 1;

        } elsif (/^(-m$|--ignore-mode$)/) {
            $opt_ignperms = 1;

        } elsif (/^(-o$|--file=)(.*)/) {
            $opt_outfile = ($1 !~ /^-[^-]/) ? $2 : ((defined($ARGV[1])) ? scalar($optval=$ARGV[1],shift @ARGV,$optval) : &ade_msg_usage(\&app_usage, 1));

        } elsif (/^--$/) {
            shift @ARGV;
	    last;

        } else {
            &ade_msg_usage(\&app_usage, 1);
        }

        shift @ARGV;
    }

    #
    #  Load option values from environment
    #

    #  (not supported by this program)

    #
    #  Load option values from config file
    #

    #  (not needed for this program)

    #
    #  hard-coded defaults
    #
    $opt_outfile  = $dflt_outfile  if (!defined($opt_outfile));
    $opt_ignowner = $dflt_ignowner if (!defined($opt_ignowner));
    $opt_igngroup = $dflt_igngroup if (!defined($opt_igngroup));
    $opt_ignperms = $dflt_ignperms if (!defined($opt_ignperms));

    #
    #  Sanity check and option rewrites
    #

    ##########################################################################
    #
    #  ARGUMENT PROCESSING
    #
    ##########################################################################

    &ade_msg_listpaths(\&app_listpaths) if ($listpaths);
    $fad1_file = $ARGV[0] || &ade_msg_usage(\&app_usage, 1);
    $fad2_file = $ARGV[1] || &ade_msg_usage(\&app_usage, 1);
    if ($fad1_file eq "-" && $fad2_file eq "-") {
        &ade_msg_errorerror("only one file can be read from standard input");
        return(1);
    }

    ##########################################################################
    #
    #  FORKING AND LOCKING
    #
    ##########################################################################

    #  (not needed for this program)

    ##########################################################################
    #
    #  GUTS STARTS HERE
    #
    ##########################################################################

    &ade_msg_debug(5, "main: opening input and output files");
    if (defined($opt_outfile)) {
        &ade_tmp_register($opt_outfile);
        if (($rc=&ade_fcm_openwritecompressed($opt_outfile, \*OUT_HANDLE)) != 0) {
            &ade_msg_errorerror("can't open $opt_outfile");
	    return($rc);
        }
        $out_handle = \*OUT_HANDLE;
    } else {
        $out_handle = \*STDOUT;
    }
        
    if ($fad1_file eq "-") {
        $fad1_handle = \*STDIN;
    } else {
        &ade_msg_debug(5, "main: opening input file $fad1_file");
        if (($rc=&ade_fcm_openreadcompressed($fad1_file, \*FAD1_HANDLE)) != 0) {
            &ade_msg_errorerror("can't open $fad1_file");
	    return($rc);
        }
        $fad1_handle = \*FAD1_HANDLE;
    }
        
    if ($fad2_file eq "-") {
        $fad2_handle = \*STDIN;
    } else {
        &ade_msg_debug(5, "main: opening input file $fad2_file");
        if (($rc=&ade_fcm_openreadcompressed($fad2_file, \*FAD2_HANDLE)) != 0) {
            &ade_msg_errorerror("can't open $fad2_file");
	    return($rc);
        }
        $fad2_handle = \*FAD2_HANDLE;
    }
    
    if (($rc=&read_fad_header($fad1_handle, undef)) != 0) {
        &ade_msg_errorerror("bad FAD header in $fad1_file");
        return($rc);
    }
    if (($rc=&read_fad_header($fad2_handle, undef)) != 0) {
        &ade_msg_errorerror("bad FAD header in $fad2_file");
        return($rc);
    }

    if (($rc=&fadstreams_to_diffstream($fad1_handle, $fad2_handle, \&faddiff_cb, $out_handle, \$diff_rc)) != 0) {
        &ade_msg_errorerror("invalid version or non fad file");
        return($rc);
    }
    &ade_msg_debug(5, "main: fadstreams_to_diffstream() returned $rc, with diff_rc $diff_rc");

    &ade_msg_debug(5, "main: closing input and output files");
    close FAD1_HANDLE if ($fad1_handle == \*FAD1_HANDLE);
    close FAD2_HANDLE if ($fad2_handle == \*FAD2_HANDLE);
    if ($out_handle  == \*OUT_HANDLE) {
        close OUT_HANDLE  
        &ade_tmp_deregister($opt_outfile);
    }

    #  The exit code is derived from whether there were differences or not.
    return $diff_rc;
}

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

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

    return(0);
}

sub app_usage
{
    print "Usage:   $main::progname [ <options> ] { <file1> | - } { <file2> | - }\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 "         -u | --ignore-uid      ignore different UIDs\n";
    print "         -g | --ignore-gid      ignore different GIDs\n";
    print "         -m | --ignore-mode     ignore different file permissions\n";
    print "         -o | --file=<outfile>  send output to <outfile> instead of stdout\n";
    print "\n";

    return(0);
}

sub app_listpaths
{
    #  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(0);
}

sub faddiff_cb
{
    my($out_handle, $file, @changes) = @_;
    my($change, $oldstate, $newstate, $hadone, $changetype);

    # &ade_msg_debug(4, "faddiff_cb: file is $file, changes are @changes");
    $hadone = 0;
    foreach $change (@changes) {
        $changetype = $change->{change_type};
        $oldstate = $change->{old_value};
        $newstate = $change->{new_value};
        ($changetype eq $main::CT_OWNER && $opt_ignowner) && next;
        ($changetype eq $main::CT_GROUP && $opt_igngroup) && next;
        ($changetype eq $main::CT_MODE  && $opt_ignperms) && next;
        if ($hadone++) {
            print $out_handle ", ";
        } else {
            print $out_handle "$file: ";
        }
        &ade_msg_debug(4, "faddiff_cb: got $changetype $oldstate $newstate");
        if ($changetype eq $main::CT_TYPE) {
            print $out_handle "type($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_OWNER) {
            print $out_handle "owner($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_GROUP) {
            print $out_handle "group($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_MODE) {
            print $out_handle "mode($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_CONT_MAJMIN) {
            print $out_handle "major/minor($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_LINKS) {
            print $out_handle "links($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_CONT_SYMLINK) {
            print $out_handle "linked_to($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_CONT_CRC) {
            print $out_handle "checksum($oldstate -> $newstate)"; 
        } elsif ($changetype eq $main::CT_ADDED) {
            print $out_handle "added()"; 
        } elsif ($changetype eq $main::CT_DELETED) {
            print $out_handle "deleted()"; 
        } else {
            #  Uncatered for change type
            &ade_err_internal("faddiff_cb: unexpected CT: $changetype");
        }
    }
    print $out_handle "\n" if ($hadone);

    &ade_msg_debug(4, "faddiff_cb: returning success ...");
    return 0;
}

#spp include fad.pl.spp
#spp include SPPSYM_ADEROOT_LIB/ade_utils.pl.spp
#spp include SPPSYM_ADEROOT_LIB/ade_gep.pl.spp
