#! /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.
#
# Converts a .sdt file to minc
# 
# Mon Oct 20 16:08:45 EDT 2003 - initial versions

use strict;
use warnings "all";
use Getopt::Tabular;
use File::Basename;

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

$me = &basename($0);
%opt = (
   'verbose' => 0,
   'clobber' => 0,
#   'byte_swap' => 0,
   );

$Help = <<HELP;
| $me converts a (.sdt|.spr) pair of file
|     (stimulate of CMRR) format images to MINC
|
| Problems or comments should be sent to: rotor\@cmr.uq.edu.au
HELP

$Usage = "Usage: $me [options] <infile.sdt> <outfile.mnc>\n".
         "       $me -help to list options\n\n";

@opt_table = (
   ["-verbose", "boolean", 0, \$opt{'verbose'},
      "be verbose"],
   ["-clobber", "boolean", 0, \$opt{'clobber'},
      "clobber existing files"],
#   ["-byte_swap", "boolean", 0, \$opt{'byte_swap'},
#      "input data requires byte swapping"],
   );

# check arguments
&Getopt::Tabular::SetHelp ($Help, $Usage);
&GetOptions (\@opt_table, \@ARGV) || exit 1;
die $Usage if ($#ARGV != 1);
$infile = $ARGV[0];
$outfile = $ARGV[1];

# check for output file
die "$me: $outfile exists, -clobber to overwrite\n\n" if (-e $outfile && !$opt{clobber});

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

# get the input basename
$inbase = $infile;
$inbase =~ s/\.(sdt|spr)$//;

# check for input files
die "$me: Couldn't find $inbase.spr\n\n" if (!-e "$inbase.spr");
die "$me: Couldn't find $inbase.sdt\n\n" if (!-e "$inbase.sdt");

# Read in the header file
my($gen_hdr) = read_sdt_header("$inbase.spr");
print STDOUT dump_general_header($gen_hdr) if $opt{verbose};

# write out the result
write_minc($gen_hdr, $outfile, "$inbase.sdt");


## subroutines ##

# read in a sdt header (.spr) and return a general header
sub read_sdt_header{
   my($infile) = @_;
   
   my($gen_hdr) = {};
   my(%hdr, $ndim, $key, $val);
   
   my(%sdt_dtypes) = ( 
      BYTE    => ['-byte', '-signed'],
      WORD    => ['-short', '-signed'],
      LWORD   => ['-int', '-signed'],
      REAL    => ['-float'],
      COMPLEX => ['-float', '-vector', 2]
      );
   
   my(%sdt_orients) = ( 
      AX      => '-transverse',
      );
   
   # first convert the header to a hash
   foreach (split(/\n/, `cat $infile`)){
      ($key, $val) = split(/\:/, $_, 2);
      
      # clean it up a bit
      $val =~ s/^(\ )*//;
      $val =~ s/\ \ /\ /g;
      $val =~ s/(\ )*$//;
      
      $hdr{$key} = $val;
      }
   
   # datatype
   if(!defined($sdt_dtypes{$hdr{dataType}})) {
      die "$me: unknown data type: $hdr{dataType}\n\n";
      }
   $gen_hdr->{datatype} = $sdt_dtypes{$hdr{dataType}};
   
#   $gen_hdr->{voxel_min} = $ana_hdr->{glmin};
#   $gen_hdr->{voxel_max} = $ana_hdr->{glmax};
#   $gen_hdr->{real_min} = $ana_hdr->{cal_min};
#   $gen_hdr->{real_max} = $ana_hdr->{cal_max};
   
   # dimension sizes, steps and starts
   (@{$gen_hdr->{sizes}}) = split(/\ /, $hdr{dim});
   (@{$gen_hdr->{starts}}) = split(/\ /, $hdr{origin});
   (@{$gen_hdr->{steps}}) = split(/\ /, $hdr{interval});
   
   # orientation
   if(!defined($sdt_orients{$hdr{sdtOrient}})) {
      warn "$me: unknown orientation $hdr{sdtOrient}, assuming transverse\n\n";
      $gen_hdr->{orientation} = '-transverse';
      }
   else{
      $gen_hdr->{orientation} = $sdt_orients{$hdr{sdtOrient}};
      }
   
   if(defined($opt{orientation})){
      warn "$me: overriding file orientation with $opt{orientation}\n";
      $gen_hdr->{orientation} = $opt{orientation};
      }
   
   return $gen_hdr;
   }

# return an ASCII dump of a general header
sub dump_general_header{
   my($h) = shift;
   my($tmp);
   
   $tmp = "General Header\n";
   foreach (sort(keys(%{$h}))){
      if($h->{$_} =~ /ARRAY/){
         $tmp .= " $_\t<". join(' ' , @{$h->{$_}}) . ">\n";
         }
      else{
         $tmp .= " $_\t<$h->{$_}>\n";
         }
      }
   $tmp .= "\n";
      
   return $tmp;
   }

# write a MINC file from a general header
sub write_minc{
   my($gen_hdr, $outfile, $infile) = @_;

   # Set up rawtominc command
   my(@args) = ('rawtominc', '-clobber');
   
   # datatype and ranges
   push(@args, @{$gen_hdr->{datatype}});
#   push(@args, '-range', $gen_hdr->{voxel_min}, $gen_hdr->{voxel_max});
   if($gen_hdr->{real_min} < $gen_hdr->{real_max}){
      push(@args, '-real_range', $gen_hdr->{real_min}, $gen_hdr->{real_max});
      }
   else{
      push(@args, '-scan_range');
      }
   
   # orientation and step information
   push(@args, $gen_hdr->{orientation},
               '-xstep', $gen_hdr->{steps}[0],
               '-ystep', $gen_hdr->{steps}[1], 
               '-zstep', $gen_hdr->{steps}[2],
               '-xstart', $gen_hdr->{starts}[0],
               '-ystart', $gen_hdr->{starts}[1],
               '-zstart', $gen_hdr->{starts}[2]);

   # files and sizes
   push(@args, '-input', $infile, 
               $outfile, 
               reverse(@{$gen_hdr->{sizes}})
               );
   
   # do the conversion
   &do_cmd(@args);
   
   # add history string
   &do_cmd('minc_modify_header', 
           '-sinsert', ":history=$history", 
           $outfile);
   }


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