#!/usr/bin/perl -w

package DVD::Maker;

use strict;

use Getopt::Long qw(GetOptions);
use File::Temp qw(tempdir);
use File::Find;
use File::Path qw(rmtree mkpath);
use File::Spec;
use File::Copy;
use File::Basename;

our $DEBUG = 0;

sub usage {
    print <<EOT;
Usage: $0 [options] Folder

    -h | --help         This screen
    -d | --debug        Debug output
    -n | --name         Name added to the DVD
    -e | --skip_empty   Skip emtpy folders
    
EOT
    exit;
}

__PACKAGE__->run unless caller;


sub new {
    my $class = shift;
    return bless {}, $class;
}

sub run {
    my $class = shift;
    
    my $self = $class->new();
    
    my $name = "";
    my $max_size = 4_508_876 * 1024;
    my $skip_empty = 0;
    
    GetOptions(
        "h|help" => \&usage,
        "d|debug" => \$DEBUG,
        "n|name" => \$name,
        "s|size" => \$max_size,
        "e|skip_empty" => \$skip_empty,
        );
    
    $self->{name} = $name;
    $self->{max_size} = $max_size;
    $self->{skip_empty} = $skip_empty,
    
    my $dir = shift(@ARGV) || usage();
    $self->{folder} = File::Spec->rel2abs($dir);
    $self->{name} ||= basename($self->{folder});
    
    die "Not a folder: $dir\n" unless -d $self->{folder};
    
    $self->process_dir();
    
    exec("open", "-a", "Disk Utility", <Disk_*.iso>);
}

#mkisofs -J -r -o TitanicCD.iso -V Titanic TitanicCD/

sub process_dir {
    my $self = shift;
    
    my $dir = $self->{folder};
    
    open(my $du, "-|", "du", "-sk", $dir) || die "du failed: $!";
    chomp(my $size = <$du>);
    close($du);
    
    $size =~ s/\s+.*$//;
    
    $size *= 1024;
    
    dbg("size of $dir: $size");
    
    if ($size < $self->{max_size}) { # approx 4.3GB - stop short of DVD size
        dbg("making ISO Disk_1.iso");
        system("mkisofs", "-J", "-r", "-o", "Disk_1.iso", "-V", $self->{name}, $dir);
        open(my $mkisofs, "-|", "mkisofs", "-J", "-r", "-o",
            "Disk_1.iso", "-V", $self->{name}, $dir) || die "mkisofs failed: $!";
        while (<$mkisofs>) {
            chomp;
            print "\r$_";
        }
        print "\n";
        close($mkisofs);
        return;
    }
    
    $self->{disk_id} = 1;
    $self->{cur_size} = 0;
    
    find({ wanted => sub { $self->wanted(@_) }, no_chdir => 1 }, $dir);
    
    # always an extra one to make at the end
    $self->mk_iso();
}

sub dbg {
    return unless $DEBUG;
    
    print @_, "\n";
}

sub wanted {
    my $self = shift;
    
    my $curr = $File::Find::name;
    
    my $relative = File::Spec->abs2rel( $curr, $self->{folder} );
    
    if (-d $curr) {
        return if $self->{skip_empty};
        # no current temp dir, so create one
        $self->{temp_dir} ||= tempdir("mk_dvd_XXXXXXXX", TMPDIR => 1);
    
        my $path = File::Spec->catdir( $self->{temp_dir}, $relative );
        dbg("Creating dir: $path");
        mkpath( $path );
        return;
    }
    
    my $rel_dir  = File::Spec->abs2rel( $File::Find::dir, $self->{folder} );
    
    if (-f $curr) {
        my $size = -s _;
        
        if ( ($self->{cur_size} + $size) > $self->{max_size} ) {
            dbg("$self->{cur_size} + $size > $self->{max_size}");
            $self->mk_iso();
        }
        
        # no current temp dir, so create one
        $self->{temp_dir} ||= tempdir("mk_dvd_XXXXXXXX", TMPDIR => 1);
        
        my $path = File::Spec->catdir( $self->{temp_dir}, $rel_dir );
        unless (-d $path) {
            dbg("Creating dir: $path");
            mkpath( $path );
        }
        
        dbg("Copying $curr -> $path");
        
        system("cp", $curr, $path) && die "cp failed!";
        
        $self->{cur_size} += $size;
    }
    else {
        warn("don't know how to handle $curr\n");
    }
    
    return;
}

sub mk_iso {
    my $self = shift;
    my $name = "$self->{name} Disk $self->{disk_id}";
    
    dbg("making ISO Disk_$self->{disk_id}.iso");
    open(my $mkisofs, "-|", "mkisofs", "-J", "-r", "-o",
        "Disk_$self->{disk_id}.iso", "-V", $name, $self->{temp_dir}) || die "mkisofs failed: $!";
    while (<$mkisofs>) {
        chomp;
        print "\r$_";
    }
    print "\n";
    close($mkisofs);
    
    $self->{disk_id}++;
    rmtree($self->{temp_dir});
    $self->{temp_dir} = undef;
    $self->{cur_size} = 0;
}