#!/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 $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 @old_order = sort {$a <=> $b} MH::message_list($FOLDER);
print STDERR "Scanned folder\n" if $VERBOSE;
for my $N (@old_order) {
  my $msg = MH::header($N);
  $field{$N} = $msg->get($FIELD);
}
print STDERR "Read 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 $aa = $field{$a};
  my $bb = $field{$b};
  for ($aa, $bb) {
    1 while s/^re:\s*//i;
    tr/A-Za-z/a-za-z/;
    tr/a-z//cd;
  }
  $REVERSE * ($aa cmp $bb || $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;
}
