#!/bin/env perl5

    # Remove duplicate files in the same directory
    # first looks for files with the same size
    use strict;

    my($start_dir,$recurse,$name_pattern,$just_list);
    my($use_tk,$state);

    my($main_win,$t_frame,$m_frame,$b_frame,$txt_area);
    my($fsdialog,$pickdir_but,$showdir_entry,$done_but,$cancel_but);
    my($report_lab);
    
    $use_tk = 1;
    $recurse = 1;
    $name_pattern = '\.jpg$';
        
    if($use_tk)
      {
        use Tk;
        use Tk::FileSelect;
        require Cwd;

        $start_dir = Cwd::getcwd();

        $main_win = new MainWindow(
            -title   => "Remove Duplicates",
          );

        $t_frame = $main_win->Frame(
          )->pack(
                -fill => 'x',
                -side => 'top',
              );

        $m_frame = $main_win->Frame(
          )->pack(
                -fill => 'x',
                -side => 'top',
              );

        $b_frame = $main_win->Frame(
          )->pack(
                -fill => 'x',
                -side => 'bottom',
              );

        $m_frame->Checkbutton(
            -text => "Subfolders",
            -variable => \$recurse,
          )->pack(
                -side => 'left'
              );

        $m_frame->Checkbutton(
            -text => "List Without Deleting",
            -variable => \$just_list,
          )->pack(
                -side => 'left'
              );

        $m_frame->Entry(
            -textvariable => \$name_pattern,
          )->pack(
                -side => 'right',
              );
        $m_frame->Label(
            -text => "Name Pattern",
          )->pack(
                -side => 'right',
              );

        # We want the main text area last so that it expands
        $txt_area = $main_win->Scrolled('Text',
            -scrollbars => 'oe',
          )->pack(
                -fill => 'both',
                -side => 'top'
              );

        $fsdialog = $main_win->FileSelect(
            -directory => '.',
          );

        $pickdir_but = $t_frame->Button(
            -text => "Browse",
            -command => \&select_dir,
          )->pack(
                -side => 'right',
                -fill => 'y',
              );

        $showdir_entry = $t_frame->Entry(
            -textvariable => \$start_dir,
          )->pack(
                -fill => 'both',
              );

        $done_but = $b_frame->Button(
            -text    => "Start",
            -command => \&start,
          )->pack(
                -side => 'left',
                -fill => 'y',
              );

        $cancel_but = $b_frame->Button(
            -text    => "Done",
            -command => sub {$main_win->destroy},
          )->pack(
                -side => 'right',
                -fill => 'y',
              );

        $report_lab = $b_frame->Label(
            -text    => $state,
          )->pack(
                -fill => 'both',
              );

        MainLoop;
      }
    else
      {
        do_dir(".");
      }
    exit(0);

sub select_dir
  {
    my($new_dir);

    $fsdialog->configure(
        -directory => $start_dir,
      );

    $new_dir = $fsdialog->Show;
    if($new_dir)
      {
        # Remove the disk specifier
 #       $new_dir =~ s/^\S://;
        $new_dir =~ s#.+(\S\:[^\:]+)$#\1#;
        if($new_dir =~ s#/+[^/]+$##)
          {
          }
        else
          {
            &add_output("Cannot parse dir from $new_dir\n");
            return;
          }
        &add_output("Set dir $new_dir\n");
        $start_dir = $new_dir;
        chdir($new_dir);
    #    $showdir_label->configure(
    #        -text => $new_dir);
      }
    else
      {
        &add_output("Canceled\n");
      }
  }

sub set_state
  {
    my($val) = @_;

    $state = $val;
    $report_lab->configure(-text => $state);
  }

sub start
  {
    &set_state("Running...");
    chdir($start_dir);
    $done_but->configure(
        -state => 'disabled',
      );
    do_dir(".");
    &set_state("Completed");
    &add_output("#"x40 . "\n");
    $done_but->configure(
        -state => 'active',
        -text => "Rerun",
      );
  }

sub add_output
  {
    # Add a line on to the current output
    my($line) = @_;

    $txt_area->insert('end',$line);
  }
  
sub do_dir
  {
    my($dir) = @_;
    my($name,@files,@subdirs,%sizes);
    local(*FILE,*DIR);

    opendir(DIR,"$dir");
    @files = readdir(DIR);
    closedir(DIR);
    
    foreach $name (@files)
      {
        my($size);

        next if($name =~ /^\./);
        if(-d "$dir/$name")
          {
            &do_dir("$dir/$name");
            next;
          }
        if($name_pattern && !eval("\$name =~ /$name_pattern/i"))
          {
            next;
          }
        $size = -s "$dir/$name";
        if($sizes{$size})
          {
            # OK this needs further looking at
            my(@s,$done,$f);
            @s = @{$sizes{$size}};
            $done = "";
            foreach $f (@s)
              {
                if(&study($dir,$f,$name))
                  {
                    $done = 1;
                    last;
                  }
              }
            if(!$done)
              {
                push(@s,$name);
                $sizes{$size} = \@s;
              }
          }
        else
          {
            my(@s);
            $s[0] = $name;
            $sizes{$size} = \@s;
          }
      }
  }

sub study
  {
    # We have a pair of candidates, they have the same size and are 
    # in the same place 
    my($dir,$n1,$n2) = @_;
    local(*F1,*F2);
    my($b1,$b2,$match);
    
    # Look at the contents of the files
    $match = 1;
    open(F1,"$dir/$n1");
    binmode(F1);
    open(F2,"$dir/$n2");
    binmode(F2);
    while(($b1 = <F1>))
      {
        $b2 = <F2>;
        if($b1 ne $b2)
          {
            $match = "";
            last;
          }
      }
    close(F1);
    close(F2);
    return(0) if(!$match);

    # OK we have a duplicate
    &remove($dir,$n2);
    return(1);
  }

sub remove
  {
    # OK this file is a duplicate, we need to remove it
    my($dir,$name) = @_;
    
    if(!$just_list)
      {
        unlink("$dir/$name");
        # Note the file we just threw away
        &add_output("Removed $dir/$name\n");
      }
    else
      {
        &add_output("Candidate $dir/$name\n");
      }
  }
