#!/usr/bin/tcsh -f

# annot2std
#
# script to create an average annotation in standard space
#
# Original Author: Doug Greve
#
# Copyright © 2021 The General Hospital Corporation (Boston, MA) "MGH"
#
# Terms and conditions for use, reproduction, distribution and contribution
# are found in the 'FreeSurfer Software License Agreement' contained
# in the file 'LICENSE' found in the FreeSurfer distribution, and here:
#
# https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
#
# Reporting: freesurfer@nmr.mgh.harvard.edu
#
#


set VERSION = 'annot2std mockbuild-local';

set target = ();
set subjlist = ();
set inannot = ();
set outannot = ();
set srcsurfreg = ();
set trgsurfreg = ();
set hemi = ();
set DoXHemi = 0;
set Overwrite = 0;
set segvote = ();
set segstack = ();

set tmpdir = ();
set cleanup = 1;
set LF = ();

set inputargs = ($argv);
set PrintHelp = 0;

if($#argv == 0) goto usage_exit;
set n = `echo $argv | grep -e -help | wc -l` 
if($n != 0) then
  set PrintHelp = 1;
  goto usage_exit;
endif
set n = `echo $argv | grep -e -version | wc -l` 
if($n != 0) then
  echo $VERSION
  exit 0;
endif
source $FREESURFER_HOME/sources.csh

goto parse_args;
parse_args_return:
goto check_params;
check_params_return:

set StartTime = `date`;
set tSecStart = `date '+%s'`;

# Set output to full path or else it goes into the target subject label dir
set outannot = `getfullpath $outannot`

set outdir = `dirname $outannot`
mkdir -p $outdir
pushd $outdir > /dev/null
set outdir = `pwd`;
popd > /dev/null

if($#tmpdir == 0) then
  set tmpdir = `fs_temp_dir --scratch --base $outdir`
endif
mkdir -p $tmpdir

# Set up log file
if($#LF == 0) set LF = $outannot.log
if($LF != /dev/null) rm -f $LF
echo "Log file for annot2std" >> $LF
date  | tee -a $LF
echo "" | tee -a $LF
echo "setenv SUBJECTS_DIR $SUBJECTS_DIR" | tee -a $LF
echo "cd `pwd`"  | tee -a $LF
echo $0 $inputargs | tee -a $LF
echo "" | tee -a $LF
cat $FREESURFER_HOME/build-stamp.txt | tee -a $LF
echo $VERSION | tee -a $LF
uname -a  | tee -a $LF

#========================================================
@ nthsubject = 0;
set segstdlist = ()
foreach subject ($subjlist)
  @ nthsubject = $nthsubject + 1;
  echo "#@# $nthsubject/$#subjlist $subject `date`" | tee -a $LF

  # Convert annotation into a segmentation
  set fname = $SUBJECTS_DIR/$subject/label/$hemi.$inannot.annot
  set seg = $tmpdir/seg.$nthsubject.$subject.mgh
  set ctab = $tmpdir/seg.$nthsubject.$subject.ctab
  set cmd = (mri_annotation2label --subject $subject --hemi $hemi \
    --seg $seg --ctab $ctab --annotation $inannot --segbase 0)
  # Force segbase=0 otherwise annotation2label sets it to non-zero
  # if aparc or aparc.2005s; this messes up mri_aparc2aseg and maybe
  # other things
  echo $cmd | tee -a $LF
  $cmd | tee -a $LF
  if($status) exit 1;
  if($nthsubject == 1) set ctab1 = $ctab

  # Map segmentation into standard space
  set segstd = $tmpdir/seg.$nthsubject.$subject.std.mgh
  set cmd = (mri_surf2surf --mapmethod nnf --hemi $hemi \
    --srcsubject $subject --srcsurfreg $srcsurfreg --sval $seg \
    --trgsubject $target  --trgsurfreg $trgsurfreg --tval $segstd)
  echo $cmd | tee -a $LF
  $cmd | tee -a $LF
  if($status) exit 1;
  set segstdlist = ($segstdlist $segstd )

  if($DoXHemi) then
    # Convert annotation into a segmentation
    set fname = $SUBJECTS_DIR/$subject/xhemi/label/$hemi.$inannot.annot
    set seg = $tmpdir/seg.$nthsubject.$subject.xhemi.mgh
    set ctab = $tmpdir/seg.$nthsubject.$subject.xhemi.ctab
    set cmd = (mri_annotation2label --subject $subject/xhemi --hemi $hemi \
      --seg $seg --ctab $ctab --annotation $inannot --segbase 0)
    echo $cmd | tee -a $LF
    $cmd | tee -a $LF
    if($status) exit 1;
    if($nthsubject == 1) set ctab1 = $ctab

    # Map segmentation into standard space
    set segstd = $tmpdir/seg.$nthsubject.$subject.xhemi.std.mgh
    set cmd = (mri_surf2surf --mapmethod nnf --srchemi $hemi \
      --srcsubject $subject/xhemi --srcsurfreg $srcsurfreg --sval $seg \
      --trgsubject $target  --trgsurfreg $trgsurfreg --tval $segstd --trghemi $hemi)
    echo $cmd | tee -a $LF
    $cmd | tee -a $LF
    if($status) exit 1;
    set segstdlist = ($segstdlist $segstd )
  endif

end

# Vote for best segmentation
if($#segvote == 0) set segvote = $tmpdir/seg.vote.mgh
set cmd = (mri_concat $segstdlist --vote --o $segvote)
echo $cmd | tee -a $LF
$cmd | tee -a $LF
if($status) exit 1;

# Get probabilities
set p = $outannot.p.mgh
set cmd = (mri_convert --frame 1 $segvote $p)
echo $cmd | tee -a $LF
$cmd | tee -a $LF
if($status) exit 1;

if(! $cleanup || $#segstack) then
  # This is a concat of all the segs, good for debugging
  if($#segstack == 0) set segstack = $tmpdir/seg.stack.mgh
  set cmd = (mri_concat $segstdlist --o $segstack)
  echo $cmd | tee -a $LF
  $cmd | tee -a $LF
  if($status) exit 1;
endif

# Create the final annotation
# Note: using the first ctab here may fail if there are parcellations in
# the segmentation that do not appear in the ctab
set cmd = (mris_seg2annot --seg $segvote --ctab $ctab1 --s $target \
  --hemi $hemi --o $outannot)
echo $cmd | tee -a $LF
$cmd | tee -a $LF
if($status) exit 1;

#========================================================

# Cleanup
if($cleanup) rm -rf $tmpdir

# Done
echo " " |& tee -a $LF
set tSecEnd = `date '+%s'`;
@ tSecRun = $tSecEnd - $tSecStart;
echo "Started at $StartTime " |& tee -a $LF
echo "Ended   at `date`" |& tee -a $LF
echo "Annot2std-Run-Time-Sec $tSecRun" |& tee -a $LF
echo " " |& tee -a $LF
echo "annot2std Done" |& tee -a $LF
exit 0

###############################################

############--------------##################
parse_args:
set cmdline = ($argv);
while( $#argv != 0 )

  set flag = $argv[1]; shift;
  
  switch($flag)

    case "--o":
      if($#argv < 1) goto arg1err;
      set outannot = $argv[1]; shift;
      breaksw

    case "--seg":
      if($#argv < 1) goto arg1err;
      set segvote = $argv[1]; shift;
      breaksw

    case "--stack":
      if($#argv < 1) goto arg1err;
      set segstack = $argv[1]; shift;
      breaksw

    case "--annot":
    case "--a":
      if($#argv < 1) goto arg1err;
      set inannot = $argv[1]; shift;
      breaksw
    case "--aparc":
      set inannot = aparc;
      breaksw
    case "--aparc.a2009s":
    case "--a2009s":
      set inannot = aparc.a2009s;
      breaksw

    case "--subject":
    case "--s":
      if($#argv < 1) goto arg1err;
      set subjlist = ($subjlist $argv[1]); shift;
      breaksw

    case "--f":
      if($#argv < 1) goto arg1err;
      set subjlistfile = $argv[1]; shift;
      if(! -e $subjlistfile) then
        echo "ERROR: cannot find $subjlistfile";
        exit 1;
      endif
      set subjlist = ($subjlist `cat $subjlistfile`);
      breaksw

    case "--fsgd":
      if ( $#argv == 0) goto arg1err;
      set fsgdf = $argv[1]; shift;
      if(! -e $fsgdf) then
        echo "ERROR: cannot find $fsgdf";
        exit 1;
      endif
      set sl = `cat $fsgdf | awk '{if($1 == "Input") print $2}'`;
      set subjlist = ($subjlist $sl);
      breaksw

    case "--lh":
      set hemi = lh
      breaksw

    case "--rh":
      set hemi = rh
      breaksw

    case "--xhemi":
      set DoXHemi = 1;
      breaksw

    case "--surfreg":
      if($#argv < 1) goto arg1err;
      set srcsurfreg = $argv[1];shift;
      set trgsurfreg = $srcsurfreg;
      breaksw

    case "--srcsurfreg":
      if($#argv < 1) goto arg1err;
      set srcsurfreg = $argv[1];shift;
      breaksw

    case "--trgsurfreg":
      if($#argv < 1) goto arg1err;
      set trgsurfreg = $argv[1];shift;
      breaksw

    case "--log":
      if($#argv < 1) goto arg1err;
      set LF = $argv[1]; shift;
      breaksw

    case "--t":
      if($#argv < 1) goto arg1err;
      set target = $argv[1]; shift;
      breaksw

    case "--nolog":
    case "--no-log":
      set LF = /dev/null
      breaksw

    case "--tmp":
    case "--tmpdir":
      if($#argv < 1) goto arg1err;
      set tmpdir = $argv[1]; shift;
      set cleanup = 0;
      breaksw

    case "--overwrite":
    case "--force":
      set Overwrite = 1;
      breaksw

    case "--nocleanup":
      set cleanup = 0;
      breaksw

    case "--cleanup":
      set cleanup = 1;
      breaksw

    case "--debug":
      set verbose = 1;
      set echo = 1;
      breaksw

    default:
      echo ERROR: Flag $flag unrecognized. 
      echo $cmdline
      exit 1
      breaksw
  endsw

end

goto parse_args_return;
############--------------##################

############--------------##################
check_params:

if($#inannot == 0) then
  echo "ERROR: must spec input annot"
  exit 1;
endif
if($#outannot == 0) then
  echo "ERROR: must spec output annot"
  exit 1;
endif
if(-e $outannot && ! $Overwrite) then
  echo "ERROR: $outannot already exists."
  echo "Choose another name, delete it, or run with --overwrite"
  exit 1;
endif
if($#hemi == 0) then
  echo "ERROR: must spec output hemi"
  exit 1;
endif
if($#subjlist == 0) then
  echo "ERROR: must spec subjects"
  exit 1;
endif
if($#target == 0) then
  echo "ERROR: must spec target subject"
  exit 1;
endif
if(! -e $SUBJECTS_DIR/$target) then
  echo "ERROR: cannot find $target in $SUBJECTS_DIR"
  exit 1;
endif
if($target != fsaverage && $#srcsurfreg == 0) then
  echo "ERROR: must spec source surf reg when target is not fsaverage"
  exit 1;
endif
if($#srcsurfreg == 0) set srcsurfreg = sphere.reg
if($#trgsurfreg == 0) set trgsurfreg = sphere.reg
foreach subject ($subjlist)
  set fname = $SUBJECTS_DIR/$subject/label/$hemi.$inannot.annot
  if(! -e $fname) then
    echo "ERROR: cannot find $fname"
    exit 1;
  endif
  set fname = $SUBJECTS_DIR/$subject/surf/$hemi.$srcsurfreg
  if(! -e $fname) then
    echo "ERROR: cannot find $fname"
    exit 1;
  endif
  if($DoXHemi) then
    set fname = $SUBJECTS_DIR/$subject/xhemi/label/$hemi.$inannot.annot
    if(! -e $fname) then
      echo "ERROR: cannot find $fname"
      exit 1;
    endif
    set fname = $SUBJECTS_DIR/$subject/xhemi/surf/$hemi.$srcsurfreg
    if(! -e $fname) then
      echo "ERROR: cannot find $fname"
      exit 1;
    endif
  endif
end

goto check_params_return;
############--------------##################

############--------------##################
arg1err:
  echo "ERROR: flag $flag requires one argument"
  exit 1
############--------------##################
arg2err:
  echo "ERROR: flag $flag requires two arguments"
  exit 1
############--------------##################

############--------------##################
usage_exit:
  echo ""
  echo "annot2std "
  echo ""
  echo "  --o outannotpath : full output path (also creates outannotpath.p.mgh)"
  echo ""
  echo "  --s subj1 <--s subj2 ... --s subjN>"
  echo "  --fsgd fsgdfile"
  echo "  --f subjectlistfile"
  echo "  --t target : target subject (eg, fsaverage)"
  echo ""
  echo "  --lh or --rh (but not both)"
  echo ""
  echo "  --xhemi (for interhemispheric analysis)"
  echo "  --surfreg surfreg (default is sphere.reg)"
  echo "  --srcsurfreg srcsurfreg (default is sphere.reg)"
  echo "  --trgsurfreg trgsurfreg (default is sphere.reg)"
  echo ""
  echo "  --a annotname : input annot (?h.annotname.annot)"
  echo "    --aparc : annotname=aparc"
  echo "    --a2009s : annotname=aparc.a2009s"
  echo ""
  echo " Good for debuggin'"
  echo "  --seg outseg.mgh : save output as a surface segmentation (2 frames, 2nd=p)"
  echo "  --stack segstack : stack of individual annots as segmentation"
  echo ""
  echo "  --help"
  echo "  --version"
  echo ""

  if(! $PrintHelp) exit 1;
  echo $VERSION
  cat $0 | awk 'BEGIN{prt=0}{if(prt) print $0; if($1 == "BEGINHELP") prt = 1 }'
exit 1;

#---- Everything below here is printed out as part of help -----#
BEGINHELP

Creates an average annotation in a standard space based on
transforming the annotations of the individual subjects to the
standard space through the surface registration. A vote is taken at
each vertex in standard space to determine which label will represent
that vertex.

The other output outannotpath.p.mgh gives a value between 0 and 1
indicating the fraction of inputs that were assigned to the winning
label.

EXAMPLE

annot2std --f b40.slist.dat --lh --aparc --o lh.aparc.std.annot --t fsaverage

This will create lh.aparc.std.annot and lh.aparc.std.annot.p.mgh

tksurfer fsaverage lh inflated -annot ./lh.aparc.std.annot -ov lh.aparc.std.annot.p.mgh -fminmax .01 1




