#!/usr/pkg/bin/perl

use File::Find;

sub printUse {
        print "\nUSAGE:\n"
            . "$0 (-r <DIR> || -f <DIR>)[-r <DIR> || -f <DIR>]* "
            . "[-g <PAT> || -G <PAT>]*\n"
            . "--Remember to use arguments in pairs.\n"
            . "  -f <DIR> picks from just the files in that directory and the"
            . " other\n           arguments.\n"
            . "  -r <DIR> picks from the files in that directory, its"
            . "   subdirectories,\n           and the other arguments.\n"
            . "  -g <PAT> picks only from those that match this pattern and"
            . " all other patterns.\n"
            . "  -G <PAT> same as -g but is case sensitive.\n"
            . "--If the output is a blank line, your patterns aren't"
            . " matching any files.\n\n";
}

### MAIN BIT ###
## This makes a big pick-list of all the files in -f <DIR>s and in -r <DIR>s
##  as well as all the -r <DIR>s subdirectories.  This list is filtered so
##  that it contains only files matching any -g or -G options.
## For example, to match only files ending in jpg, jpeg, JPG and JPEG, use
##  -g 'jpe?g$' [quote or escape the '$' from your shell]

if ($#ARGV % 2 == 0 || $#ARGV == -1) {
        printUse;
        print "ERROR: Incorrect number of arguments.\n\n";
        exit(1);
}

# EXPLAIN the following bit;
# this makes two hashes, the first (%argrev) uses the argument as the key, and
#  stores the meaning   [ie "-r . -f .. -f /etc" becomes: 
#                       ( '.'    => '-r',
#                         '..'   => '-f',
#                         '/etc' => '-f' ) ]
# the second (%arg) uses the meaning as the key, and stores the argument(s) 
# in a list.    [ie the above becomes:
#               ( '-r' => ('.'),
#                 '-f' => ('..', '/etc') ) ]
my %argrev = reverse @ARGV;
my %arg;
foreach (keys %argrev) { 
        push(@{$arg{$argrev{$_}}}, $_); 
}
##showing that it worked
#print "\%argrev:\n";
#print map { "$_ => " . $argrev{$_} . "\n" } keys %argrev; print "\n";
#print "\%arg:\n";
#print map { "$_ => (@{$arg{$_}})\n" } keys %arg; print "\n";
#exit(0);

# end EXPLAINed bit;

  if (!exists $arg{'-r'} && !exists $arg{'-f'}) {
        printUse;
        print "ERROR: Did not have at least one -r or -f type\n\n";
        exit(0);
  }

{
  my @badarg = grep { ($_ ne '-r' && $_ ne '-f' && $_ ne '-G' && $_ ne '-g')  }
                    keys %arg;
  my $counter = 0;
  foreach (@badarg) {
    $counter++;
  }
  if ($counter != 0) {
    printUse;
    print "\n";
    foreach (@badarg) {
      print "ERROR: We don't support the operation $_.\n";
    }
    exit(1);
  }
}


my @picklist;

foreach (@{$arg{"-r"}}) {
        push (
          @picklist,
          recurseDir( verifyDir( fixDir($_) ) )
        );
}
foreach (@{$arg{"-f"}}) {
        push (
          @picklist,
          getDir( verifyDir( fixDir($_) ) )
        );
}
print pickFrom(@picklist);
print "\n";

### END MAIN BIT ###

sub filter {
#return true if we match the filters
#print "filter: $_[0]\n";
        my $str = $_[0];
        foreach (@{$arg{"-g"}}) {               #case insensitive
                if ($str !~ m/$_/i) {return 0;} #if false ret false
        }
        foreach (@{$arg{"-G"}}) {               #case sensitive
                if ($str !~ m/$_/) {return 0;}  #if false ret false
        }
        return 1;                               #else true
}

sub fixDir {
#append a closing / if needed;
        if ($_[0] =~ m/\/$/) {
                return $_[0];
        } else {
                return $_[0] . "/";
        }
}

sub verifyDir {
#check if the file is a directory
        if (!-d $_[0])
        {
                printUse;
                print "ERROR: \"$_[0]\" is not a directory.\n\n";
                exit(1);
        }
        return $_[0];
}

sub pickFrom {
#pick a random out of the passed in list
        return( $_[ rand @_] );
}

sub recurseDir {
#check a directory tree return all filenames with path.
        my @ret;
        find( sub { if (filter ($_)) {push(@ret, $File::Find::name);} },
              $_[0]
            );
        return @ret;
}

sub getDir {
#check directory all filenames with path.
        if (!opendir(DIR, $_[0])){
                die "$_[0] is Not a directory!\n";
        }
        my @dir = readdir(DIR);
        closedir(DIR);
        @dir = grep {filter ($_)} @dir;
        foreach(@dir){$_ =~ s/.*/$_[0]$&/;}
        return @dir;
}