#!/usr/bin/perl
use warnings;
use Getopt::Long;
use File::Copy;

$cmd = $0;
my $prog_name = "Picker - directory picker for CD/DVD collection";
my $prog_version = "v0.1.1";
my $prog = $prog_name . " " . $prog_version;
my $release_date = "2004-10-08";
my $copy = "Copyright (C) Peter Ivanov <ivanovp_at_freemail_dot_hu>, 2004";

my $main_dir = ".";
my $media_size = 2298496 * 2 - 10; # kilobytes
my $move_dest_dir;
my $copy_dest_dir;
my $dest_dir;
my $copy_prog;
my $exit = 0;
#select STDOUT; $| = 0; # make unbuffered
my $verbose = 0;

GetOptions ('s|media-size:i' => \$media_size,
            'd|main-dir:i'   => \$main_dir,
            'm|move:s'       => \$move_dest_dir,
            'c|copy:s'       => \$copy_dest_dir,
            'h|help'         => sub { usage (); $exit = 1; },
            'v|version'      => sub { version (); $exit = 1; },
            'V|verbose'      => sub { $verbose = 1; },
            'copyright'      => sub { copyright (); $exit = 1; },
            'dvd47'          => sub { $media_size = 2298496 * 2 - 10 },
            'dvd9'           => sub { $media_size = 2298496 * 4 - 10 },
            'cd800'          => sub { $media_size = 800 * 1024 - 10 },
            'cd700'          => sub { $media_size = 702 * 1024 - 10 },
            'cd650'          => sub { $media_size = 654 * 1024 - 10 }
            );

exit if $exit;

if (defined $copy_dest_dir) {
    $copy_prog = "cp";
    $dest_dir = $copy_dest_dir;
}
if (defined $move_dest_dir) {
    $copy_prog = "mv";
    $dest_dir = $move_dest_dir;
}

print "Main directory: $main_dir\n";
print "Destination directory: $dest_dir\n" if defined $dest_dir;
print "Media size: ", hsize ($media_size), "\n";
print "\n";

my @dirs;
my %dir_size;
@ARGV = ("du -k --max-depth=1 $main_dir |");
while (<>) {
    my ($size, $name) = split;
    unless ($name eq $main_dir) {
        $dir_size{$name} = $size;
        push @dirs, $name;
    }
}

my $dir_num = @dirs; # number of directories
die "No directories\n" if ($dir_num == 0);
print "Directories:\n";
print_dirs (@dirs);

my @orig_dirs = @dirs;
my @collections;
my $i = 0;
my $j = 1;
my $variations = $dir_num * ($dir_num - 1);
my $best_size = 0;
my $best_collection = -1;

do {
    my $s = 0;
    foreach $name (@dirs) {
        last if $s + $dir_size{$name} >= $media_size;
        push @{$collections[$j]}, $name;
        $s += $dir_size{$name};
    }
    if ($s > $best_size) {
        $best_size = $s;
        $best_collection = $j;
    }
    #print "\nCollection #$j:\n";
    #print_dirs (@{$collections[$j]});
    
    @dirs[$i, $i + 1] = @dirs[$i + 1, $i];
    $i++;
    $i = 0 if ($i == $dir_num - 1);
} while ($j++ < $variations);

die "Sorry. No best pick :(\n" if ($best_collection == -1);

print "Best pick:\n";
my @bestpick = @{$collections[$best_collection]};
print_dirs (@bestpick);
if (defined ($dest_dir)) {
    if (!-d $dest_dir) {
        print "Creating $dest_dir...\n";
        mkdir ($dest_dir);
    }
    print "Moving/copying best pick to $dest_dir...\n";
    foreach $name (@bestpick) {
        print `$copy_prog -vi $name $dest_dir`;
    }
}
if ($verbose > 0) {
    print "Calculated collections:\n";
    for ($i = 1; $i < $variations; $i++) {
        if ($i < $variations - 1 && @{$collections[$i]} != @{$collections[$i + 1]}) {
            print "Collection #$i\n";
            print_dirs (@{$collections[$i]});
        }
        elsif ($i == $variations - 1  && @{$collections[$i]} != @{$collections[$i - 1]}) {
            print "Collection #$i\n";
            print_dirs (@{$collections[$i]});
        }
    }
}

exit 1;

############################################################################
# print directories list
sub print_dirs
{
    my (@dirs) = @_;
    my $s = 0;
    foreach $name (@dirs) {
        my $size = $dir_size{$name};
        $s += $size;
        printf "%10s %s\n", hsize ($size), $name;
    }
    print "Size: ", hsize ($s), "\n\n";
}

############################################################################
# human readable size
sub hsize
{
    my ($size) = @_;
    return $size . " KiB" if $size < 1000;
    return sprintf "%.02f MiB", ($size / 1024) if $size < (1000*1024);
    return sprintf "%.02f GiB", ($size / 1024 / 1024);
}

############################################################################
sub version
{
    print "$prog\n";
    print "Released: $release_date\n";
}

sub usage
{
    print<<EOT;
$prog
$copy

This program comes with ABSOLUTELY NO WARRANTY; for details type `$cmd --copyright'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `$cmd --copyright' for details.

Usage: $cmd [-d <directory>] [-s <disc size>] [-c <directory>] [-m <directory>] [-h] [-v] [-C]
Options:
  -d or --main-dir:   main directory
  -s or --media-size: size of media in kilobytes
  -c or --copy:       copy best pick to directory
  -m or --move:       move best pick to directory
  -h or --help:       prints help
  -v or --version:    prints version
  -V or --verbose:    verbose output
  --copyright:        prints copyright informations

Predefined media sizes: --dvd47, --dvd9, --cd800, --cd700, --cd650
EOT
}

sub copyright
{
    print<<EOT;
$prog
$copy

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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

EOT
}

