#!/usr/bin/perl

use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../lib/perl5lib";

use File::Feed;
use File::Kvpar;
use Getopt::Long
    qw(:config posix_default gnu_compat require_order bundling no_ignore_case);

usage() if !@ARGV;

my $cmd = shift;
my $code = __PACKAGE__->can("cmd_$cmd") or usage();
$code->();

sub cmd_create {
    my %opt;
    die "Not yet implemented";
}

sub cmd_channels {
    #> channels [FEED]
    #.
    my $dir = @ARGV ? shift @ARGV : '.';
    my $feed = File::Feed->new($dir);
    print $_, "\n" for sort map { $_->id } $feed->channels;
}

sub cmd_fill {
    #> fill [OPTIONS...] [FEED]
    #| basic options:
    #|      -c CHANNEL  Channels to fill (repeatable)   [all]
    #| output options:
    #|      -q          Exit status indicates result    [off]
    #|      -n          Print only number of files      [off]
    #|      -m          Print results in kvpar format   [off]
    #|      -v          Be verbose                      [off]
    #.
    unshift @_, 'fill';
    goto &_fill_or_new;
}

sub cmd_new  {
    #> new [OPTIONS...] [FEED]
    #| basic options:
    #|      -c CHANNEL  Channels to check (repeatable)  [all]
    #| output options:
    #|      -q          Exit status indicates result    [off]
    #|      -n          Print only number of files      [off]
    #|      -m          Print results in kvpar format   [off]
    #|      -v          Be verbose                      [off]
    #.
    unshift @_, 'new_files';
    goto &_fill_or_new;
}

sub cmd_drain {
    #> drain [OPTIONS...] [FEED] [SINK...]
    #| basic options:
    #|      -c CHANNEL  Channels to drain (repeatable)  [all]
    #| output options:
    #|      -q          Exit status indicates result    [off]
    #|      -n          Print only number of files      [off]
    #|      -m          Print results in kvpar format   [off]
    #|      -v          Be verbose                      [off]
    #| examples:
    #|      ffeed drain
    #|      ffeed drain $feed
    #|      ffeed drain . '/tmp/%(file.path)'
    #|      ffeed drain $feed 'kit:pickup/%(datetime).%(project).kit'
    #.
    my (%arg, %opt);
    GetOptions(
        # Things we pass to the feed instance
        'c=s@' => \$arg{'channels'},
        # Output options
        'q'    => \$opt{'q'},
        'n'    => \$opt{'n'},
        'm'    => \$opt{'m'},
        'v'    => \$opt{'v'},
    ) or usage();
    push @ARGV, '.' if @ARGV == 0;
    my $dir = shift @ARGV;
    $arg{'sinks'} = [@ARGV] if @ARGV;
    my @out = File::Feed->new($dir)->drain(%arg);
    exit(@out ? 0 : 1) if $opt{'quiet'};
    if ($opt{'n'}) {
        print scalar(@out), "\n";
    }
    elsif ($opt{'m'}) {
        File::Kvpar->new(\*STDOUT)->write(@out);
    }
    elsif ($opt{'v'}) {
        printf "%s <= %s\n", $_->local_path, $_->path for @out;
    }
    else {
        print $_->local_path, "\n" for @out;
    }
}

sub cmd_reset {
    #> reset [FEED]
    #.
    push @ARGV, '.' if @ARGV == 0;
    my $dir = shift @ARGV;
    my $feed = File::Feed->new($dir);
    $feed->reset;
}

sub cmd_freeze {
    #> freeze [FEED]
    #.
    push @ARGV, '.' if @ARGV == 0;
    my $dir = shift @ARGV;
    my $feed = File::Feed->new($dir);
    $feed->freeze;
}

sub cmd_thaw {
    #> thaw [FEED]
    #.
    push @ARGV, '.' if @ARGV == 0;
    my $dir = shift @ARGV;
    my $feed = File::Feed->new($dir);
    $feed->thaw;
}

sub cmd_status {
    #> status [FEED]
    #.
    push @ARGV, '.' if @ARGV == 0;
    my $dir = shift @ARGV;
    my $feed = File::Feed->new($dir);
    my $status = $feed->status;
    print substr($status, 1), "\n";
}

sub _fill_or_new {
    my $method = shift;
    my (%opt, %arg);
    GetOptions(
        # Things we pass to the feed instance
        'c=s@' => \$arg{'channels'},
        # Output options
        'q'    => \$opt{'q'},
        'n'    => \$opt{'n'},
        'm'    => \$opt{'m'},
        'v'    => \$opt{'v'},
    ) && @ARGV == 1 or usage();
    my $feed = File::Feed->new(@ARGV);
    my @new = $feed->$method(%arg);
    exit(@new ? 0 : 1) if $opt{'q'};
    if ($opt{'n'}) {
        print scalar(@new), "\n";
    }
    elsif ($opt{'m'}) {
        File::Kvpar->new(\*STDOUT)->write(@new);
    }
    elsif ($opt{'v'}) {
        printf "%s <= %s\n", $_->local_path, $_->path for @new;
    }
    else {
        print $_->local_path, "\n" for @new;
    }
}

sub usage {
    if (@_) {
        print STDERR 'usage: ffeed ', shift(), "\n";
    }
    elsif (defined $cmd && open my $fh, '<', $0) {
        my $started;
        while (<$fh>) {
            if (s/^ *#> $cmd\b//) {
                print STDERR 'usage: ', $cmd, $_;
                $started = 1;
            }
            elsif (s/^ *#\| //) {
                print STDERR $_ if $started;
            }
            elsif (/^ *#\./) {
                last if $started;
            }
        }
    }
    else {
        print STDERR <<'EOS';
usage: ffeed COMMAND [ARG...]
commands:
    create          Create a new feed
    fill            Fill a feed with new files
    new             List new files in a feed
    drain           Move new files to DIR
EOS
    }
    exit 1;
}
