#!/bin/bash
# ================================================================================
#
# RESTORE - interactive restore
#
# Restore duplicity backup data to a local directory.
# Please notice: duplicity does not overwrite any dir or file. So the restore
# path is different to the path of the backed up data.
#
# SYNTAX:
# restore.sh [path-to-restore]
#
#   path-to-restore - optional
#   default: none ... you get an interactive selection of backup sets
#
# --------------------------------------------------------------------------------
# ah - Axel Hahn <axel.hahn@iml.unibe.ch>
# ds - Daniel Schueler <daniel.schueler@iml.unibe.ch>
#
# 2016-11-17  ah,ds  v1.0
# 2017-10-11  ah,ds  v1.1  added support for duplicity param --ssh-backend
# 2018-08-27  ah,ds  v1.2  fix restore target with a given selection; handle '*' placeholder
# 2019-06-05  ah,ds  v1.3  add custom cache dir
# 2021-05-19  ah,ds, v2.0  plugin driven 
# 2022-10-21  ah     v2.1  init vars; shell fixes
# 2024-02-01  ah     v2.2  update restore menu
# ================================================================================


# --------------------------------------------------------------------------------
# CONFIG
# --------------------------------------------------------------------------------

  # . `dirname $0`/inc_config.sh

  . $(dirname $0)/includes/jobhelper.sh || exit 1
  . $(dirname $0)/includes/inc_bash.sh  || exit 1

  # --- load a transfer plugin
  STORAGE_BIN=$(_j_getvar ${STORAGEFILE} "bin")

  if [ -z "$STORAGE_BIN" ]; then
    if ! id -u | grep '^0$'
    then
      cecho error "ERROR: Maybe you need root permissions to start $0"
    else
      cecho error "ERROR: missing config bin = ... for file transfer."
    fi
    exit 1
  fi

  CFGPREFIX=${STORAGE_BIN}_

  . $(dirname $0)/plugins/transfer/$STORAGE_BIN.sh || exit 1

  # --- get backend url of backup data
  STORAGE_BASEDIR=$(_j_getvar ${STORAGEFILE} "storage")
  if [ -z $STORAGE_BASEDIR ]; then
    echo "ERROR: missing config for backup target."
    echo "There must be an entry storage in ${STORAGEFILE}"
    exit 1
  fi

  # target directory of directory specific repository
  STORAGE_TARGETPATH=

  PASSPHRASE=$(_j_getvar "${STORAGEFILE}" "passphrase")

  # timestamp or snapshot id
  RESTORE_ITEM=

  # include filter to restore a part of the backup set
  RESTORE_FILTER=

  # full path of restore data
  RESTORE_BASEDIR=$(_j_getvar "${STORAGEFILE}" "restore-path")
  RESTORE_TARGETPATH=

  # set vars for transfer plugin
  t_setVars || exit 1


  # ----- Create default command line parameters
    export ARGS_DEFAULT
    ARGS_DEFAULT="$( t_getParamDefault $1 $2 )"
    sFileSshPrivkey=$(_j_getvar "${STORAGEFILE}" "ssh-privatekey")
    if [ -n "$sFileSshPrivkey" ]; then
      ARGS_DEFAULT="${ARGS_DEFAULT} $( t_getParamSshKey $sFileSshPrivkey )"
    fi


    # task#3046 - add custom cache dir
    sCacheDir=$(_j_getvar "${STORAGEFILE}" "cachedir")
    ARGS_DEFAULT="${ARGS_DEFAULT} $( t_getParamCacheDir $sCacheDir )"


  # ----- what to restore ...
  BACKUP_DIR= 



# --------------------------------------------------------------------------------
# FUNCTIONS
# --------------------------------------------------------------------------------

# ----------------------------------------------------------------------
# enter name of directory to restore; menu item
# ----------------------------------------------------------------------
function enterBackupDir(){

  h2 "select a directory to be restored"

  echo "This is a list of the directories from the backup configuration."
  echo "Enter the full path"
  echo

  echo "Enter the full path; marked entries with (*) do not exist on this machine"
  echo

  local sDirs="$(j_getDirs2Backup)"
  for mydir in $sDirs
  do
    if [ ! -d "$mydir" ]; then
      color error
      echo "$mydir (*)"
      color reset
    else
      echo "$mydir"
    fi
  done

  color input
  echo -n "[$BACKUP_DIR] >"
  color reset
  read -r myinput

  setBackupDir "${myinput}"

}


# ----------------------------------------------------------------------
# set backup dir .. called when using cli parameter or enterBackupDir
# param  string   full path of a directory to retore
# ----------------------------------------------------------------------
function setBackupDir(){
  if [ ! -z $1 ]; then
    sDirs2Backup="$(j_getDirs2Backup)"
    bFound=0
    for mydir in ${sDirs2Backup}
    do
      if [ "${mydir}" = "${1}" ]; then
        bFound=1
      fi
    done

    if [ $bFound -eq 0 ]; then
      color error
      echo
      echo "WARNING: seems to be wrong ... "
      echo "At the moment I restore only known targets."
      color reset

      # TODO: if we want to retore other backup sets of other servers
      # we cannot be as strict

    else

      BACKUP_DIR=$1
      setVars
    fi
  fi
}

# ----------------------------------------------------------------------
# internal: set variables for target path and backup set 
# ----------------------------------------------------------------------

# set backup url and local restore path (based on given backup directory)
function setVars(){
  local sSafeName=$(j_getSafename "$BACKUP_DIR")
  RESTORE_TARGETPATH="${RESTORE_BASEDIR}/${sSafeName}"
  STORAGE_TARGETPATH="$( t_backupDirGetTarget $BACKUP_DIR )"
}

# actions for restore
function doRestore(){
  local restorecmd=$( t_restoreDoRestore )
  if [ -z "$restorecmd" ]; then
    color error
    echo "ERROR: There is no restore command ... "
    echo "A developer must check t_restoreDoRestore in plugins/transfer/$STORAGE_BIN.sh"
    color reset
    exit 1
  fi

  mkdir -p "${RESTORE_TARGETPATH}"
  echo "$restorecmd"
  color cmd
  $restorecmd
  fetchrc
  color reset

  t_rcCheckRestore $myrc

  echo
  echo
  echo Restore is finished.
  echo Have look to the output above.
  echo "The restore path has $(find ${RESTORE_TARGETPATH} | wc -l) items ($(du -hs ${RESTORE_TARGETPATH} | awk '{ print $1 }'))"
  echo 
  echo "    find ${RESTORE_TARGETPATH}"
  echo 
  exit

}


# --------------------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------------------

# ----- set a directory to restore to have a useful initial point

  t_checkRequirements

  setBackupDir $1
  if [ -z "$BACKUP_DIR" ]; then
    enterBackupDir
  fi

# ----- menu and loop

  while true
  do

    h1 "Restore :: Menu"

    echo " D - directory to restore: $( color cmd ; echo -n $BACKUP_DIR; color reset)"
    echo
    echo "---------- Restore method 1:"
    echo
    echo " M - mount backup with fuse"
    echo
    echo "---------- Restore method 2:"
    echo
    echo -n " W - time or snapshot ID : $( color cmd ; echo -n $RESTORE_ITEM; color reset)"
      test -z "$RESTORE_ITEM" && echo -n " ... set one first"
      test -z "$RESTORE_ITEMINFO" || echo -n " ($RESTORE_ITEMINFO)"
      echo
    echo -n " F - what to restore     : $( color cmd ; echo -n $RESTORE_FILTER; color reset)"
      test -z "$RESTORE_FILTER" && echo -n "(no filter = restore all files)"
      echo
    echo
    # echo " C - show file changes"
    # echo " V - verify"
    # echo
    echo " R - start restore with $STORAGE_BIN"
    echo
    echo "     restore from         : $STORAGE_TARGETPATH" | sed 's#:[^:]*@#:**********@#'
    echo "     restore to           : $( color cmd ; echo -n $RESTORE_TARGETPATH; color reset)"
    echo -n "                            "
    if [ -n "$RESTORE_TARGETPATH" ]; then
      ls -d "$RESTORE_TARGETPATH" >/dev/null 2>&1
      if [ $? -eq 0 ]; then
        color error
        echo "WARNING: directory already exists! Backup will fail."
        color reset
      else
        echo "OK, it does not exist yet"
      fi
    else
      echo "(not set)"
    fi
    echo
    echo "---------- Other options:"
    echo
    echo " S - search files"
    echo " B - Bash (Shell)"
    echo " X - exit"
    echo

    showPrompt "Select (not case sensitive) --> "
    read -r action
    echo

    case $action in
      d|D)
        enterBackupDir
        ;;
      w|W)
        h2 "Set a time / select a snapshot"
        t_restoreDoSelect
        ;;
      c|C)
        showFilechanges
        ;;
      m|M)
        h2 "Mount backup data"
        t_restoreDoMountBackupdata
        ;;
      s|S)
        h2 "Search a file"
        filefilter=".*"
        showPrompt "Regex for filefilter; ${filefilter} for all >"
        read -r filefilter
        test -z "${filefilter}" || t_restoreDoSearchFile "${filefilter}"
        ;;
      # v|V)
      #   t_backupDoVerify
      #   ;;
      b|B)
        h2 "Shell"
        echo "HINT: type exit in the subshell to return to the menu."
        echo
        export PS1="RESTIC [$(basename $0) \u@\h \w]\$ "
        bash --noprofile
        ;;
      f|F)
        h2 "Filter restore items"
        echo "By default all files will be restored."
        echo "You can limit it by setting include rules."
        t_restoreDoSetIncludeFilter
        ;;
      r|R)
        h2 "Start restore"
        doRestore
        ;;
      x|X)
        exit 0
        ;;
      *)
        echo "Try again"
    esac


  done


# --------------------------------------------------------------------------------