#!/usr/bin/perl
my $FOLDER;
my $FIELD = 'subject';
my $REVERSE = 1;  # -1 means reverse, 1 means forward
use lib '/home/mjd/perl/lib';
use MH;

my $VSCALE = 1;

my $BAD;
while (@ARGV) {
  local $_ = shift;
  if (/^\+(.*)/) {
    $FOLDER = $1;
  } elsif (/^(-f|-fi|-fie|-fiel|-field)$/) {
    $FIELD = shift;
  } elsif (/^(?:-v|-ve|-ver|-verb|-verbo|-verbos|-verbose)$/) {
    $VERBOSE = 1;
  } elsif (/^(?:-r|-re|-rev|-reve|-rever|-revers|-reverse)$/) {
    $REVERSE = -1;
  } elsif (/^-/) {
    warn "Unrecognized option '$_'\n";
    $BAD=1;
  } else {
    $BAD=1;
  }
}
usage() if $BAD;

$FOLDER = MH::current_folder() unless defined $FOLDER;
my %field;
my $N = my @old_order = sort {$a <=> $b} MH::message_list($FOLDER);
my $s = "s" unless $N == 1;
$VSCALE *= 3 until $N / $VSCALE < 80;
print STDERR "Scanned folder ($N message$s)\n" if $VERBOSE;
print STDERR '|', '-' x ceil($N/$VSCALE - 2), "|\n" if $VERBOSE;
for my $mn (@old_order) {
  my $msg = MH::header($mn, $FOLDER);
  $field{$mn} = $msg->get($FIELD);
  print STDERR "." if $VERBOSE && $Vcounter++ % $VSCALE == 0;
}
print STDERR "\nRead messages\n" if $VERBOSE;

my @new_order = sort comparator @old_order;
@new_number{@new_order}  = @old_order;
for my $m (keys %new_number) {
  delete $new_number{$m} if $new_number{$m} == $m;
}

my $dir = MH::mhpath($FOLDER);
while (%new_number) {
  my ($cur) = keys %new_number;
  my @chain;
  do {
    push @chain, $cur;
    $cur = delete $new_number{$cur};
  } while $cur != $chain[0];
  print STDERR "Chain: (@chain)\n" if $VERBOSE;
  
  my ($prev, @rest) = reverse @chain;
  my $TMP = "$prev.TMP";
  rename("$dir/$prev", "$dir/$TMP") or die "$prev => $TMP: $!";
  for my $cur (@rest) {
    rename("$dir/$cur", "$dir/$prev") or die "$cur => $prev: $!";
    $prev = $cur;
  }
  rename("$dir/$TMP", "$dir/$prev")  or die "$TMP => $prev: $!";
}


sub comparator {
  my @F = @field{$a, $b};
  my @re_count;
  for my $i (0 .. 1) {
    for ($F[$i]) {
      $re_count[$i]++ while s/^re:\s*//i;
      tr/A-Za-z/a-za-z/;
      tr/a-z//cd;
    }
  }
  $REVERSE * (lc $F[0] cmp lc $F[1]
              || $re_count[0] <=> $re_count[1]
              || $field{$a} cmp $field{$b}
              );  
}

sub usage {
  warn <<EOM;
Usage: $0 [-field fieldname] [-verbose] [-reverse] [+foldername]
Sort messages in folder alphabetically by contents of specified field
Default field: 'Subject'
Default folder: current folder
-reverse: Reverse sort order
Flags may be abbreviated to any unambiguous prefix.  (-r instead of -reverse)
EOM
  exit 1;
}

sub ceil {
  my $x = shift;
  return $x == int($x) ? $x : int($x) + 1;
}
