#! /usr/bin/env perl
#
# Andrew Janke - a.janke@gmail.com
# Center for Magnetic Resonance
# The University of Queensland
#
# Copyright Andrew Janke, The University of Queensland.
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies.  The
# author and the University of Queensland make no representations about the
# suitability of this software for any purpose.  It is provided "as is"
# without express or implied warranty.

$| = 1;

use strict;
use warnings "all";
use Getopt::Tabular;
use File::Basename;
use File::Temp qw/ tempdir /;

# until I get organised and do this properly
my $PACKAGE = &basename($0);
my $VERSION = '1.3.0';
my $PACKAGE_BUGREPORT = '"Andrew Janke" <a.janke@gmail.com>';

my($Help, $Usage, $me, @opt_table, $history, %opt);
my($infile, $outxfm, $outfile);

$me = &basename($0);
%opt = (
   'verbose' => 0,
   'quiet' => 0,
   'clobber' => 0,
   'fake' => 0,
   'tmpdir' => undef,
   'keeptmp' => 0,
   'mirror_dim' => 'x',
   'method' => 'minctracc',
   'align_center' => 'voxel',
   );

$Help = <<HELP;
| $me is designed to align MINC file about its axis of symmetry.
|    This is done via registering an image to a flipped version of
|    itself and halving the resulting xfm with xfmavg.
|
| Problems or comments should be sent to: a.janke\@gmail.com
HELP

$Usage = "Usage: $me [options] <infile.mnc> <align.xfm> [<outfile.mnc>]\n".
         "       $me -help to list options\n\n";
@opt_table = (
   ["General Options", "section" ],
   ["-version", "call", 0, \&print_version_info,
      "print version and exit" ],
   ["-verbose", "boolean", 0, \$opt{'verbose'},
      "be verbose" ],
   ["-quiet", "boolean", 0, \$opt{'quiet'},
        "be quiet)" ],
   ["-clobber", "boolean", 0, \$opt{'clobber'},
      "clobber existing files" ],
   ["-fake", "boolean", 0, \$opt{'fake'},
      "do a dry run, (echo cmds only)" ],
   ["-tmpdir", "string", 1, \$opt{'tmpdir'},
      "temporary directory to use" ],
   ["-keeptmp", "boolean", 1, \$opt{'keeptmp'},
      "keep the tmpdir after processing (dont delete)" ],


   ["Registration options", "section" ],
   ["-x",  "const", 'x', \$opt{'mirror_dim'},
      "mirror in the x dimension [default]" ],
   ["-y",  "const", 'y', \$opt{'mirror_dim'},
      "mirror in the y dimension" ],
   ["-z",  "const", 'z', \$opt{'mirror_dim'},
      "mirror in the z dimension" ],
   ["-minctracc",  "const", 'minctracc', \$opt{'method'},
      "Use minctracc [default]" ],
   ["-mritoself",  "const", 'mritoself', \$opt{'method'},
      "Use mritoself" ],
   ["-voxel",  "const", 'voxel', \$opt{'align_center'},
      "Align about the center voxel of the volume [default]" ],
   ["-world",  "const", 'world', \$opt{'align_center'},
      "Align about world co-ordinate 0,0,0" ],
   );

# get history string
chomp($history = `date`);
$history .= '>>>> ' . join(' ', $me, @ARGV);

# check args
&Getopt::Tabular::SetHelp($Help, $Usage);
&GetOptions(\@opt_table, \@ARGV) || exit 1;
die $Usage if ($#ARGV < 1);

# make tmpdir
if(defined($opt{'tmpdir'})){
   # just in case
   &do_cmd('mkdir', '-p', $opt{'tmpdir'});
   $opt{'tmpdir'} = &tempdir( "$me-XXXXXXXX", DIR => $opt{tmpdir}, CLEANUP => (($opt{'keeptmp'}) ? 0 : 1) );
   }
else{
   $opt{'tmpdir'} = &tempdir( "$me-XXXXXXXX", TMPDIR => 1, CLEANUP => (($opt{'keeptmp'}) ? 0 : 1) );
   }

# get file names
$infile = shift(@ARGV);
$outxfm = shift(@ARGV);
$outfile = ($#ARGV > -1) ? shift(@ARGV) : undef;

# check for files
if(!-e $infile){
   die "$me: Couldn't find input file: $infile\n\n";
   }
if(-e $outxfm && !$opt{'clobber'}){
   die "$me: $outxfm exists, -clobber to overwrite\n\n";
   }
if(defined $outfile && -e $outfile && !$opt{'clobber'}){
   die "$me: $outfile exists, -clobber to overwrite\n\n";
   }

# a bit of output
if(!$opt{'quiet'}){
   print STDOUT " | infile:  $infile\n";
   print STDOUT " | xfm:     $outxfm\n";
   print STDOUT " | outfile: $outfile\n" if defined($outfile);
   }

# figure out the symmetry center
my(@center);
if($opt{'align_center'} eq 'world'){
   # make the inversion transform
   &do_cmd('param2xfm', '-clobber',
      '-center', 0, 0, 0,
      '-scales' ,
      ($opt{'mirror_dim'} eq 'x') ? -1 : 1,
      ($opt{'mirror_dim'} eq 'y') ? -1 : 1,
      ($opt{'mirror_dim'} eq 'z') ? -1 : 1,
      "$opt{'tmpdir'}/inv.xfm");

   &do_cmd('mincresample', '-clobber',
      '-use_input_sampling',
      '-transformation', "$opt{'tmpdir'}/inv.xfm",
      $infile, "$opt{'tmpdir'}/flip-$opt{'mirror_dim'}.mnc");
   }

elsif($opt{'align_center'} eq 'voxel'){
   # flip the input file
   &do_cmd('volflip', '-clobber',
      "-$opt{'mirror_dim'}",
      $infile, "$opt{'tmpdir'}/flip-$opt{'mirror_dim'}.mnc");
   }

else{
   die "$me: This shouldn't happen, something is broken\n\n";
   }


# create a registration xfm file
&do_cmd($opt{'method'}, '-clobber',
        '-xcorr', '-lsq6',
        (($opt{'method'} eq 'minctracc') ? '-est_center' : ()),
        $infile, "$opt{'tmpdir'}/flip-$opt{'mirror_dim'}.mnc",
        "$opt{'tmpdir'}/reg.xfm");

if($opt{'verbose'}){
   my $line;
   foreach $line (`xfm2param $opt{'tmpdir'}/reg.xfm`){
      print STDOUT " | $line";
      }
   }

# make ident xfm
&do_cmd('param2xfm', "$opt{'tmpdir'}/ident.xfm");

# Make the 1/2 xfm
&do_cmd('xfmavg', '-clobber',
        '-ignore_nonlinear',
        "$opt{'tmpdir'}/ident.xfm", "$opt{'tmpdir'}/reg.xfm",
        $outxfm);

# create the resampled file if required
if(defined $outfile){
   print STDOUT "Creating $outfile...\n" if !$opt{quiet};
   &do_cmd('mincresample', '-clobber',
           '-use_input_sampling',
           '-transformation', $outxfm,
           $infile, $outfile);

   # add the history string to the output file
   &do_cmd('minc_modify_header',
      '-sappend', ":history='$history'",
      $outfile);
   }



sub do_cmd {
   print STDOUT "@_\n" if $opt{'verbose'};
   if(!$opt{'fake'}){
      system(@_) == 0 or die;
      }
   }


sub print_version_info {
   print STDOUT "\n$PACKAGE version $VERSION\n".
                "Comments to $PACKAGE_BUGREPORT\n\n";
   exit;
   }
