#!/bin/sh

#   Nov 25/16   S. Kharin (Simplify and remove more junk)
#   Nov 2016    N. Swart  (Migrate to sqlite database and remove junk)
#   Dec 23/08 - F.Majaess (Change default to "link" mode, "nocp=no" forces "cp")
#   May 25/05 - F.Majaess (Use "-L" instead of parsing "file" command output)
#   Jan 21/99 - F.Majaess (Added yo/yonaka)
#   Jul 14/97 - F.Majaess (Revise for hiru)
#   Aug 26/96 - F.Majaess (Revise to use "samefs" instead of relying on "df")
#   Jul 15/96 - F.Majaess (Revise for SX4)
#   Dec 08/95 - F.Majaess (Replace 'hostname' calls by "$HOSTID")
#   Sep 25/95 - F. Majaess (Add '-h' to 'file' on SGI)
#   Aug 15/95 - F. Majaess (Implement 'scanobe' switch feature)
#   Jun 05/95 - F. Majaess (Re-enable checking sx3 from sx3r)
#   May 29/95 - F. Majaess (temporarily disable checking sx3 from sx3r)
#   Feb 13/95 - F. Majaess (enforce "pfn" to be in lower case)
#   Jan 04/95 - F. Majaess (Add nocp switch)
#   Nov 16/94 - F. Majaess (Modify for sx3r)
#   Jan 31/94 - F. Majaess (Ensure error detection due to filesystem failure)
#   Dec 29/93 - F. Majaess (Modify for accessing files from other than
#                           "$RUNPATH")
#   Nov 25/92 - E. Chan (Modify for accessing files across multiple file
#                        systems)
#   Sep 10/91 - E. Chan

#id access - creates a symbolic link to a file saved using the "save" script

#   AUTHOR  - E. Chan

#hd PURPOSE - If "nocp=no"; then:
#hd            "access" copies the permanent dataset into "fn" file in the
#hd             current directory as well as creating ".fn"_Link soft link
#hd             to the permanent dataset.
#hd           otherwise,
#hd            "access" creates a symbolic link to a file residing in either
#hd             the user's own '$RUNPATH' directory, or in some other file
#hd             system,  as well as creating ".fn"_Link soft link
#hd             to the permanent dataset.
#hd
#hd           By default, the link is made to the highest edition of the file
#hd           in the directory (the edition number is included in the filename
#hd           as a three digit extension following a period).

#pr PARAMETERS:
#pr
#pr   POSITIONAL
#pr
#pr     fn     = name of link in directory from which "access" is invoked
#pr
#pr     pfn    = name of saved file
#pr
#pr   PRIMARY
#pr
#pr     ed     = edition number of saved file (default: the latest edition)
#pr
#pr
#pr   PRIMARY/SECONDARY
#pr
#pr     na     = switch that, if set, ensures the return of exit status 0
#pr              (i.e. 'no abort') even if access fails (=''/'na')
#pr
#pr     nocp   = switch which can be set to 'no' (ie. "nocp=no") in order
#pr              to force making a local "fn" copy of the targeted "pfn".
#pr              (='yes'/'no')
#pr
#ex EXAMPLE:
#ex
#ex     access data datfile ed=3
#ex
#ex     The above example creates a symbolic link called 'data' in the
#ex     directory from which "access" is invoked to 'datfile.003'.
#ex
#ex     access data datfile ed=3 nocp=no
#ex
#ex     The above will result in copying 'datfile.003' into 'data' file in the
#ex     subdirectory from which 'access' was invoked.
#ex     A link '.data_Link' pointing to 'datfile.003' is established.
#ex

#  * Reset field separators (otherwise those defined in the parent process
#  * will be used and these may cause problems if they include special
#  * characters used in this script).

IFS=' '
export IFS

#  * Capture command line arguments in "arg_list"

arg_list=$@

#  * Obtain the file names and any specified option.

for arg in $arg_list
do
  case $arg in
      -*) set $arg                                         ;;
    ed=*) ed=`expr $arg : 'ed=\([0-9]*\)'`                 ;;
     *=*) eval "$arg"                                      ;;
      na) na='na'                                          ;;
    nocp) nocp='yes'                                       ;;
       *) tmp1=${fn:+$arg} ; pfn=${pfn:=$tmp1}              ;
          fn=${fn:=$arg}
  esac
done
echo fn=$fn pfn=$pfn

#  * Set the error level based on the 'na' option. Also set the file
#  * status parameter (=0 if $fn exists and >0 if $fn doesn't exist).

if [ -n "$na" ] ; then
  error='Warning'
  level=0
else
  error='  Abort'
  level=1
fi

#  * Set variable 'AWK' to the version of "awk" to be used.

AWK=${AWK:='awk'}

# Enable the following line to have default (ie. to favour) "link" setup.
nocp=${nocp:='yes'}
if [ "$nocp" = 'on' ] ; then
 nocp='yes'
elif [ "$nocp" = 'off' ] ; then
 nocp='no'
fi
pfn=`echo $pfn | tr '[A-Z]' '[a-z]'`

#  * Format edition number
if [ -n "$ed" ] ; then
  ed=`echo $ed | $AWK '{printf "%03d",$1}'`
fi

if [ -e "$fn" ] ; then
  echo "$error in ACCESS: $fn already exists"
  exit $level
fi

# replace colons with spaces
DATAPATH_DBs=`echo $DATAPATH_DB | sed 's/:/ /g'`
# number of databases
ndbs=`echo $DATAPATH_DBs | wc -w`
# 1st database
DATAPATH_DB1=`echo $DATAPATH_DBs | cut -f1 -d' '`

#  * Loop over all databases until file is found
ndb=0
for DATAPATH_DB in $DATAPATH_DBs ; do
export DATAPATH_DB
ndb=`expr $ndb + 1`

# create an empty database if it does not exist
if [ ! -s $DATAPATH_DB ] ; then
  fdb empty
fi

#  * Extract the absolute path to the desired file.
ntrymax=50 # maximum number of attempts to retrieve file name from the database.
ntry=1
while true ; do
  file=$(fdb -t path $pfn $ed) && status="$?" || status="$?"
  echo status=$status $file
  if [ $status -eq 0 ]; then
    # fdb was successful and file is found in the current database
    break 2 # break out 2 loop levels up
  elif [ $status -eq 1 ]; then
    # fdb was successful but file is not in the current database
    if [ $ndb -lt $ndbs ] ; then
      echo "Warning in ACCESS: File $pfn does not exist in the database $DATAPATH_DB. $file status=$status ndb=$ndb"
      # go to the next database
      break
    else
      # no databases left
      echo "$error in ACCESS: File $pfn does not exist in the database $DATAPATH_DB. $file status=$status ndb=$ndb"
    fi
    exit $level
  else
    # fdb failed - try again.
    if [ $ntry -gt $ntrymax ] ; then
      echo "Abort in ACCESS: Failure in fdb. $file ntry=$ntry status=$status ndb=$ndb"
      echo `date -u +'%Y-%m-%d %H:%M:%S'` $USER "Abort in ACCESS: Failure in fdb $DATAPATH_DB. $file ntry=$ntry status=$status ndb=$ndb" >> ${DATAPATH_DB}_failures.txt
      # fdb failed.
      exit 1
    else
      echo "Warning in ACCESS: Failure in fdb. $file ntry=$ntry status=$status ndb=$ndb"
      echo `date -u +'%Y-%m-%d %H:%M:%S'` $USER "Warning in ACCESS: Failure in fdb $DATAPATH_DB. $file ntry=$ntry status=$status ndb=$ndb" >> ${DATAPATH_DB}_failures.txt
      sleep 10
    fi
  fi
  ntry=$((ntry+1))
done # ntry
done # DBs

#  * Extract the path and compare against the current filesystem.
#  * If the file resides on the same filesystem as the current
#  * subdirectory then create a symbolic link to that file with
#  * the name '$fn', otherwise, copy the file into the current
#  * directory possibly from a remote back-end machine.

Lfn=.${fn}_Link
(\rm -f $Lfn 2>/dev/null || : )
if [ "$nocp" != 'no' ] ; then
   # make symlink
  echo "make softlink"
   ln -s $file $fn
   if [ "$?" -ne 0 ] ; then
     echo "$error in ACCESS: link $fn can not be established"
     echo "                  to file $file"
     exit $level
   fi
else
   samefs $file .
   status=$?
   if [ $status -eq 0  -a `stat -c '%U' $file` = `stat -c '%U' .` ] ; then
     # if files reside on the same file system and belong to the same user, make hard links
     if [ ! -d $file ] ; then
       echo "make hardlink to a single file"
       ln $file $fn
     else
       echo "make hardlinks to all files in a directory"
       mkdir -p $fn
       ln $file/* $fn/
     fi
   else
     # otherwise, make a copy
     echo "make copy"
     cp -Lrp $file $fn
     chmod -R u+w $fn
   fi
   if [ "$?" -ne 0 ] ; then
     echo "$error in ACCESS: file $file has not been copied"
     echo "                  into $fn"
     exit $level
   fi

#  * Setup .${fn}_Link link to keep track where the local file came
#  * from.

   ln -s $file $Lfn
   if [ "$?" -ne 0 ] ; then
     echo "$error in ACCESS: link $Lfn can not be established"
     echo "                  to file $file"
     exit $level
   fi
fi

exit
