#!/usr/bin/env bash

function get_checksum()
{
    if [ "$os" == "linux" ]; then
      checksum=`$md5_cmd $1 | awk '{print $1}'`
    else
      checksum=`$md5_cmd $1 | awk '{print $4}'`
    fi
    echo $checksum
}

if [ -z $FREESURFER_HOME ]; then
    echo "*** Error: Environment variable FREESURFER_HOME must be defined in order to apply updates." 
    exit 1
fi
if [[ ! $FREESURFER_HOME =~ 8\.[0-9]\.[0-9] ]]; then
   echo "*** Error: FREESURFER_HOME=$FREESURFER_HOME must point to an installed 8.X.X"
   exit 1
fi
if [ ! -e $FREESURFER_HOME/bin ]; then
   echo "*** Error: Cannot stat $FREESURFER_HOME/bin - exiting."
   exit 1
fi

echo $FREESURFER_HOME | grep "8\.2\.0" > /dev/null
grep_stat=$?
if [ $grep_stat -ne 0 ]; then
   echo "FREESURFER_HOME=$FREESURFER_HOME does not point to an 8.2.0 release - exiting."
   exit 1
fi

url=""
if [ ! -z ${2} ]; then 
   url=$2
fi
if [ "$url" == "" ]; then
   url="https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/.fs820_updates"
fi
# echo "URL = $url"

if [ -e /usr/bin/sw_vers ]; then
   # host_cmd="sw_vers -productVersion"
   host_cmd="uname -a"
   md5_cmd="md5"
   os="macos"
elif [ -e /etc/os-release ]; then
   host_cmd="grep PRETTY_NAME /etc/os-release"
   md5_cmd="md5sum"
   os="linux"
else
   echo "*** Error: Could not find expected OS ident files - exiting."
   exit 1
fi

host_ident=`$host_cmd | sed 's;^.*=;;'`
context="null"

if [[ $host_ident =~ Darwin.*arm64 ]]; then
   context="darwin_arm64"
elif [[ $host_ident =~ Darwin.*x86_64 ]]; then
   context="darwin_x86_64"
elif [[ $host_ident =~ "CentOS Linux 7" ]]; then
   context="centos7_x86_64"
elif [[ $host_ident =~ "Rocky Linux 9" ]]; then
   context="rocky9_x86_64"
elif [[ $host_ident =~ "Rocky Linux 8" ]]; then
   context="rocky8_x86_64"
elif [[ $host_ident =~ "Ubuntu 24" ]]; then
   context="ubuntu24_x86_64"
elif [[ $host_ident =~ "Ubuntu 22" ]]; then
   context="ubuntu22_x86_64"
else
   echo "*** Error: machine with OS identity = \"$host_ident\" is unrecognized - exiting."
   exit 1
fi
echo "Machine context is $context"

if [[ $context =~ [Dd]arwin ]]; then
   fetch_cmd="curl -f -O"
else
   fetch_cmd="wget"
fi

rm -f default
${fetch_cmd}  $url/default
if [ $? -ne 0 ]; then
   echo "*** Error: download of default config failed - if this error persists please notify the Freesurfer team."
   exit 1
fi
if [ ! -e default ]; then
   echo "*** Error: Could not stat existing default spec - exiting."
   exit 1
fi
if [ ! -s default ]; then
   ls -l default
   rm -f default
   echo "*** Error: Downloaded File \"default\" is zero length - please check with the Freesurfer team."
   exit 1
fi

patch_default=`cat default`
patch_arg=""
patch_found=""
if [ ! -z "$1" ]; then 
   patch_arg=$1
fi

# see if there is an existing arhive file, e.g., patch_data_20250405.tgz
ls patch_data_2*.tgz > /dev/null
ls_stat=$?

# argument archive file from command line is 1st choice
if [ "$patch_arg" != "" ]; then
   echo "Using argument archive file = $patch_arg"
   patch=$patch_arg
# otherwise, check if youngest archive file matches the default
elif [ $ls_stat -eq 0 ]; then
   lsfile=`ls patch_data_2*.tgz | sort -r | head -1`
   if [ "$lsfile" != "$patch_default" ]; then
      # default archive should supercede any existing archive file found with a younger timestamp in its name
      echo "Youngest downloaded $lsfile name does not match required default $patch_default"
      patch=$patch_default
   else
      echo "Found existing $lsfile matching required default $patch_default"
      patch=$lsfile
   fi
else
   echo "No existing patch_data_2*.tgz archive file found."
   patch=$patch_default
fi
patch_dir=`echo $patch | sed 's;\.tgz;;'`

# Try to download if the archive file does not exist

if [ ! -e $patch ]; then
   echo "Attempting to dowload archive file $patch."

   $fetch_cmd $url/$patch
   if [ $? -ne 0 ]; then
      echo "*** Error: download of patch data failed - if this error persists please notify the Freesurfer team."
      exit 1
   fi

   # Assume downloaded file with timestamp in its name is younger then the timestamp in the name of pre-existing archive files

   if [ ! -e $patch ]; then
      echo "*** Error: Could not stat file \"$patch\"after download - exiting."
      exit 1
   fi
   if [ ! -s $patch ]; then
      ls -l $patch
      rm -f $patch
      echo "*** Error: Downloaded File \"$patch\" is zero length - please check with the Freesurfer team."
      exit 1
   fi
fi

### DEBUG
# echo "Will apply files in $patch to install under $FREESURFER_HOME"
# ls -l "$patch"

# Note this will change the timestamp on the ./bin subdir but not the parent, e.g., 8.2.0, directory
# The timestamp will change anyway if something is being patched under ./bin
touch $FREESURFER_HOME/bin/dummy_file > /dev/null
if [ $? -ne 0 ]; then
   echo "You may need to run this script with sudo/root privileges in order to update the freesurfer installation."
   echo "*** Error: Cannot write to $FREESURFER_HOME/bin - exiting."
   exit 1
else
   rm -f $FREESURFER_HOME/bin/dummy_file
fi

rm -rf $patch_dir
tar zxpf $patch

if [ ! -e $patch_dir ]; then
   echo "*** Error: Could not unarchive $patch - exiting."
   exit 1
fi

this_dir=$PWD
cd $patch_dir/$context
if [ $? -ne 0 ]; then
   echo "*** Error: Cannot cd to $patch_dir/$context - exiting."
fi

for file in $(find . -name "*.checksum"); do
    
    # get the reference checksum saved in the arhive
    csum_ref=`cat $file`
    patch_file=`echo $file | sed 's;\.checksum;;'`
    msg_file=`echo $file | sed 's;\.checksum;\.msg;'`
    echo ""
    echo "-------- Processing $patch_file --------"

    # test checksum of file in archive after download
    csum_new=$(get_checksum $patch_file)
    if [ "$csum_ref" != "$csum_new" ]; then
       # echo "*** Error: Checksum for $patch_file does not match reference - exiting."
       # exit 1
       echo "*** Error: Checksum for $patch_file does not match reference - skipping this file."
    else
       echo "checksum of downloaded file OK."

       target_file="$FREESURFER_HOME/$patch_file"   
       force_file="${patch_file}.force"

       skip="false"
       compare_csum="true"
       force="false"
       if [ ! -e $target_file ] && [ -e $force_file ]; then
          # file does not exist in the installed distro and there is a *.force entry for it in the patch archive
          force="true"
          # so no installed file to checksum to compare to archive version checksum
          compare_csum="false"
       fi
       if [ ! -e $target_file ] && [ "$force" == "false" ]; then
          # otherwise skip processing this file in the patch archive since it is not installed
          skip="true"
       fi

       if [ "$skip" == "true" ]; then
          echo "*** Error: Cannot stat file $target_file to replace - skipping this file."
       else
          # test checksum of existing file in freesurfer distribution prior to udpate
          if [ "$force" == "true" ]; then
             # file not installed in distro, so force checksum mismath against empty string
             csum_old=""
          else
             csum_old=$(get_checksum $target_file)
          fi
          if [ "$csum_ref" == "$csum_old" ]; then
             echo "Existing file $FREESURFER_HOME/$patch_file is the same as file in patch archive - nothing to do."
          else
             if [ -e $msg_file ]; then
                echo -n "Remarks for this update: "
                cat $msg_file
             fi
             read -p "Update $FREESURFER_HOME/$patch_file? [Yy/Nn]: " -n 1 -r
             echo
             if [[ ! $REPLY =~ ^[Yy]$ ]]; then
                echo "Skipping replacing $FREESURFER_HOME/$patch_file"
             else
                pwd
                echo "tar cpf - $patch_file | (cd $FREESURFER_HOME && tar xvpf -)"
                tar cpf - $patch_file | (cd $FREESURFER_HOME && tar xvpf -)
                if [ $? -ne 0 ]; then
                   # echo "*** Error: Update failed - continuing."
                   echo "*** Error: Update failed - exiting."
                   exit 1
                fi
                # test checksum after update
                csum_patch=$(get_checksum $target_file)
                if [ "$csum_ref" == "$csum_patch" ]; then
                   echo "Checksum OK after update."
                else
                   # echo "*** Error: Update failed - continuing."
                   echo "*** Error: Update failed - exiting."
                   exit 1
                fi
             fi
          fi
       fi
    fi
done

cd $this_dir
if [ -e $patch_dir ]; then
   chmod -R 777 $patch_dir
   sleep 1
   find $patch_dir ! -type d -exec rm -f {} \; 
   sleep 1
   rm -rf $patch_dir
   rm -f $patch
fi
 
