#!/usr/pkg/bin/perl

use lib qw(); # PERL5LIB
use lib qw(/usr/pkg/lib); # LIBDIR

use Getopt::Long qw(:config posix_default no_ignore_case);
use Pod::Usage;

use Mojo::Base -strict;
use Mojo::Log;
use ZnapZend::Config;
use ZnapZend::ZFS;
my $VERSION = '0.dev'; #VERSION
my $zConfig;
my $zZfs;
my $zTime = ZnapZend::Time->new();

sub dumpStats {
    my $stats = shift;
    my $tabs = shift;
    my $setup = shift;

    if (! $tabs) {
       print ' ' x (5 - length($stats->{usage}));
    }
    print $stats->{usage};
    print ($tabs ? "\t" : "   ");
    print "$stats->{last_snap}";
    print ($tabs ? "\t" : "   ");
    print "$stats->{dataset}";
    if ($setup) {
       print ($tabs ? "\t" : "   ");
       print "$stats->{definitionDataset}";
       print ($tabs ? "\t" : "   ");
       print "$stats->{key}";
    }
    print "\n";
}

sub collectData {
    my $definitionDataset = shift;
    my $key = shift;
    my $dataset = shift;
    my $snapFilter = shift;
    my %data;
    my $snapshots = $zZfs->listSnapshots($dataset, $snapFilter);

    $data{usage} = $zZfs->usedBySnapshots($dataset);
    my $lastSnap = $snapshots->[-1] // ' @No Snapshots Yet  ';
    ($data{last_snap}) = $lastSnap =~ /^.+\@([^\@]+)$/;
    $data{dataset} = $dataset;
    $data{definitionDataset} = $definitionDataset;
    $data{key} = $key;

    return \%data;
}

sub main {
    my $opts = {};

    GetOptions($opts, qw(H help|h recursive|r only-enabled inherited pfexec debug sudo rootExec=s man timeWarp=i setup)) or exit 1;

    if ($opts->{pfexec}) {
        warn "--pfexec is deprecated. Use --rootExec=pfexec instead\n";
        $opts->{rootExec} = 'pfexec';
    } elsif ($opts->{sudo}) {
        warn "--sudo is deprecated. Use --rootExec=sudo instead\n";
        $opts->{rootExec} = 'sudo';
    }

    if (defined($opts->{debug})) {
        $opts->{debug} = ( $opts->{debug} eq 'off' ? 0 : 1 );
    } else {
        $opts->{debug} = 0;
    }

    my $zLog = Mojo::Log->new();
    $zZfs = ZnapZend::ZFS->new(zLog => $zLog,
        rootExec => $opts->{rootExec},
        debug => $opts->{debug});
    $zConfig = ZnapZend::Config->new(zLog => $zLog,
        rootExec => $opts->{rootExec},
        timeWarp => $opts->{timeWarp},
        debug => $opts->{debug});

    $opts->{help} && do {
        pod2usage(-exitval => 'NOEXIT');

### RM_COMM_4_TEST ###  # remove ### RM_COMM_4_TEST ### comments for testing purpose.
### RM_COMM_4_TEST ###  $opts = {};

        return 1;
    };
    $opts->{man} && pod2usage(-exitstatus => 0, -verbose => 2);

    # MAYBE make $enabledOnly parameter public in Config.pm
    my $recurse = (defined($opts->{"recursive"}));
    my $inherit = (defined($opts->{"inherited"}));
    my $backupSets = ($opts->{"only-enabled"}
        ? $zConfig->getBackupSetEnabled($recurse, $inherit, pop @ARGV)
        : $zConfig->getBackupSet($recurse, $inherit, pop @ARGV))
        or die "ERROR: cannot list backup config\n";

    #check if there is at least one valid backup set
    @$backupSets or die "ERROR: no valid znapzend setup found on source\n";

    my $dummyTime = $zTime->createSnapshotTime(time + ($opts->{timeWarp} // 0), $backupSets->[0]->{tsformat});

    #print header
    if (!$opts->{H}) {
        my $padlen = (length($dummyTime) - length('LAST SNAPSHOT'));;
        $padlen = 0 if ($padlen < 0);
        print 'USED    LAST SNAPSHOT' . ' ' x $padlen . ($opts->{H} ? "\t" : "   ") . "DATASET";
        if ($opts->{setup}) {
            print '        SETUP FS       SETUP KEY';
        }
        print "\n";
    }

    for my $backupSet (@$backupSets){
        my $datasets = $backupSet->{recursive} eq 'on' && $opts->{recursive}
            ? $zZfs->listSubDataSets($backupSet->{src}) : [$backupSet->{src}];

        # TOTHINK: Consider forcedSnapshotSuffix here? Not really known outside of bin/znapzend anyway...
        my $snapFilter = $zTime->getSnapshotFilter($backupSet->{tsformat});

        #source dataset
        for my $dataset (@$datasets){
            dumpStats(collectData($backupSet->{src}, "src", $dataset, $snapFilter), $opts->{H}, $opts->{setup});

            #destination datasets
            for (keys %$backupSet){
                my ($key) = /^(dst_[^_]+)$/ or next;

                #skipping destination if it does not exists
                if (!$backupSet->{$key . '_valid'}){
                    print "*** WARNING: destination '$backupSet->{$key}'"
                        . " does not exist! ***\n\n";
                }
                else{
                    my $dstDataSet = $dataset;
                    $dstDataSet =~ s/^$backupSet->{src}/$backupSet->{$key}/;
                    dumpStats(collectData($backupSet->{src}, $key, $dstDataSet, $snapFilter), $opts->{H}, $opts->{setup});
                }
            }

        }
    }
    return 1;
}

main();

1;

__END__

=head1 NAME

znapzendztatz - znapzend statistics utility

=head1 SYNOPSIS

B<znapzendztatz> [I<options>...] [src_dataset]

 --debug        print debugging details from some library routines
 -H             do not print headers and separate fields by a single tab
                instead of arbitrary white space
 -r,--recursive show statistics for dataset and sub datasets
 --inherited    allow to specify a dataset which just inherits a backup plan
 --only-enabled only show statistics for enabled datasets
 --setup        show the configuration key and the filesystem that defined the configuration
 --rootExec=x   exec zfs with this command to obtain root privileges (sudo or pfexec)
 --timeWarp=x   act as if you were shifted by x seconds into the future
 --man          show man-page and exit
 -h,--help      display this help and exit

=head1 DESCRIPTION

znapzendztatz shows statistics of snapshots created and storage space usage

=head1 COPYRIGHT

Copyright (c) 2014 by OETIKER+PARTNER AG. All rights reserved.

=head1 LICENSE

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see L<http://www.gnu.org/licenses/>.

=head1 AUTHOR

S<Tobias Oetiker E<lt>tobi@oetiker.chE<gt>>
S<Dominik Hassler E<lt>hadfl@cpan.orgE<gt>>

=head1 HISTORY

2014-06-29 had Flexible snapshot time format
2014-06-05 had Initial Version

=cut
