# Execute this script before packaging

# This script searches $prefix for ELF (executables or shared objects).
# Whenever it finds one, it replaces RPATH of the file.
# e.g.
#   RPATH=/opt/hscpipe/VERSION/Linux64/MODULE/VERSION/lib
#   =>    $ORIGIN/../lib

#Reuire $prefix, $lsst_home, $hscpipe_ver
recreate_elf()
(
  set -e

  source "${lsst_home}"/loadLSST.bash
  setup hscPipe "${hscpipe_ver}"

  # Get relative path of target from viewpoint.
  # e.g.
  #   target     /abc/def/ghi/jkl.h
  #   viewpoint  /abc/def/mno/pqr.c
  # => relpath   ../ghi/jkl.h
  RelPath()
  (
    local target="$1"
    local viewpoint="$2"

    local dir="$(dirname "$viewpoint")"

    #split paths
    local oldIFS="$IFS"
    IFS="/"
    target=($target)
    dir=($dir)
    IFS="$oldIFS"

    #how far are they similar?
    local i
    for((i = 0; i < ${#dir[@]}; ++i))
    do
      if [[ "${dir[i]}" != "${target[i]}" ]]
      then
        break
      fi
    done

    local common=$i

    #make relative path
    local relpath=()
    for((i = ${#dir[@]}; i > common; --i))
    do
      relpath+=("..")
    done

    relpath+=(${target[@]:common})

    oldIFS="$IFS"
    IFS="/"
    relpath="${relpath[*]}"
    IFS="$oldIFS"

    echo "$relpath"
  )


  # Get required rpath
  RequiredPath()
  (
    local file="$1"

    # get required directories with the use of ldd
    local x
    local y
    local z
    local w
    rpathUsed=":"
    while read -r x y z w
    do
      [[ "$y" != "=>" ]] && continue
      [[ "$z" != "/"* ]] && continue

      z="$(dirname "$z")"
      [[ "$rpathUsed" != *":$z:"* ]] && rpathUsed+="$z:"

      x=
      y=
      z=
      w=
    done <<< "$(ldd "$file")"

    local ORIGIN="$(dirname "$file")"

    # Analyze RPATH and copy it to rpathNew

    eval local rpath=\""$(patchelf --print-rpath "$file")"\"

    #split rpath by ':'
    local oldIFS="$IFS"
    IFS=":"
    local rpathlist=($rpath)
    IFS="$oldIFS"

    local rpathNew=":"

    local k
    for((k = 0; k < ${#rpathlist[@]}; ++k))
    do
      [[ -z "${rpathlist[k]}" ]] && continue

      [[ "$rpathNew" != *":${rpathlist[k]}:"*
      ]] && {
        rpathNew+="${rpathlist[k]}:"
      }
    done

    # Analyze LD_LIBRARY_PATH and append it to rpathNew as needed

    #split LD_LIBRARY_PATH by ':'
    local oldIFS="$IFS"
    IFS=":"
    local rpathlist=($LD_LIBRARY_PATH)
    IFS="$oldIFS"

    local k
    for((k = 0; k < ${#rpathlist[@]}; ++k))
    do
      [[ -z "${rpathlist[k]}" ]] && continue

      [[ "$rpathUsed" = *":${rpathlist[k]}:"*
      && "$rpathNew" != *":${rpathlist[k]}:"*
      ]] && {
        rpathNew+="${rpathlist[k]}:"
      }
    done

    # If rpathNew is not empty, print it

    [[ "$rpathNew" != ":" ]] && echo "${rpathNew:1:${#rpathNew}-2}"
  )


  ForceUseOrigin()
  (
    local rpath="$1"
    local file="$2"

    #split rpath by ':'
    local oldIFS="$IFS"
    IFS=":"
    local rpathlist=($rpath)
    IFS="$oldIFS"

    local k
    for((k = 0; k < ${#rpathlist[@]}; ++k))
    do
      if [[ "${rpathlist[k]}" = "$prefix"* ]]
      then
        local relpath="$(RelPath "${rpathlist[k]}" "$file")"
        if [[ -z "$relpath" ]]
        then
          rpathlist[k]='$ORIGIN'
        else
          rpathlist[k]='$ORIGIN/'"$relpath"
        fi
      fi
    done

    #join rpath by ':'
    oldIFS="$IFS"
    IFS=":"
    rpath="${rpathlist[*]}"
    IFS="$oldIFS"

    echo "$rpath"
  )


  find "$prefix" \( \! -type l \) -print0 |
  while read -r -d '' file
  do
    local rpath
    if [[ "$(file -b "$file")" = "ELF"* ]]
    then
      patchelf --print-rpath "$file" &> /dev/null || continue

      local rpath="$(RequiredPath "$file")"
      rpath="$(ForceUseOrigin "$rpath" "$file")"

      echo "patchelf $file -> $rpath"

      local mode="$(stat -c '%a' "$file")"
      chmod 777 "$file"
      patchelf --set-rpath "$rpath" "$file"
      chmod "$mode" "$file"
    fi
  done
)
