#! /bin/sh

# -------------------------------------------------------------
# --- init
# -------------------------------------------------------------

# leave on error
set -e

# set program name and location:
call="$0 $*"
case $0 in
  /* ) script=$0 ;;
  *  ) script="`/bin/pwd`/$0" ;;
esac
bindir=`/usr/bin/dirname ${script}`
prog=`/bin/basename ${script}`


# -------------------------------------------------------------
# --- help
# -------------------------------------------------------------

DisplayUsage ()
{
${PAGER:-less} << EOF

NAME
  $prog  -  General Storage System : ECMWF tape archive (ECFS)
  

USAGE

  ${prog} ls [-l,--long] <ecfsfilespec>
    
      -l, --long    : long listing including modes, times, sizes etc

  ${prog} get [-f,--force] [-m,--mkdir] <source-ecfsfilespec> <dest-filespec>
  ${prog} put [-f,--force] [-m,--mkdir] <source-ecfsfilespec> <dest-filespec>
  
      -f, --force   : overwrite existing destination files if necessary;
                      by default, an error is produced if a file on ecfs
                      already exists (ecp -e)
      -m, --mkdir   : create destination directories if necessary

  
FILE SPECIFICATION

  A file on ecfs is specified by a standard unix file name:

    /ab1/TM/meteo         # permanent storage 'ec:'
    /TMP/ab1/TM/meteo     # temporary storage 'ectmp:'
    
  Special options are preceded, seperate with percent signs:

    umask=022%/ab1/TM/meteo


FILE ACCESS PERMISSIONS  
  
  Default umask: 077 = --- rwx rwx

  Thus new direcory : rwx rwx rwx  XOR  --- rwx rwx  =  rwx --- ---
  and new file      : rw- rw- rw-  XOR  --- rwx rwx  =  rw- --- ---
  
  Change mask to exclude only write permissions for 'group' and 'other':
    umask=022    # --- -w- -w-


GENERAL OPTIONS
  -v, --verbose   : display info on progress


EOF
exit 0
}


# err 'help text'
err ()
{
  echo "$1" 1>&2
}


# errit <exit-status>
errit ()
{
  err "$prog - ERROR - from : ${call}"
  err "$prog - ERROR - Use '$prog --help' for more info."
  exit $1
}


# -------------------------------------------------------------
# --- arguments
# -------------------------------------------------------------

options=''
task=''
filespecs=''

verbose=''

# extract arguments
for arg in "$@" ; do
  case ${arg} in
    -h | --help    ) DisplayUsage  ;;
    -v | --verbose ) verbose='T' ;;
    -* ) options="${options} ${arg}" ;;
    * ) # task or (one of the) file(s)
      if [ -z "${task}" ]; then
        task=${arg}
      else
        filespec=${arg}
        filespecs="${filespecs} ${filespec}"
      fi
      ;;
  esac
done

# not complete ?
if [ -z "${task}" ]; then
  err "$prog - no arguments specified"
  errit 1
fi


# -------------------------------------------------------------
# --- functions
# -------------------------------------------------------------

#
# EvalSpecials umask=022%group=ksarch%/fa/ks/TM
# filespec=${FS}
#
#   Evaluates all preceding parts ending with '%'.
#   Return last part in variable 'FS' .
#

EvalSpecials ()
{
  # seperation mark:
  sep='%'
  
  # loop until all % parts are removed:
  FS=$1
  while [[ ${FS} = *%* ]]; do
    eval "`echo ${FS} | /usr/bin/cut -d ${sep} -f 1`"
    FS=`echo ${FS} | /usr/bin/cut -d ${sep} -f 2-`
  done
}


# -------------------------------------------------------------
# --- begin
# -------------------------------------------------------------

test ${verbose}  &&  echo "$prog - $0 $*"

# setup script present ?
case `/bin/hostname` in
  ecga* ) 
    . '/usr/local/share/ecmwf/share/.kshrc'
    ;;
  ecgb* )
    . "${ECFS_SYS_PATH}/.ecfs_bash_env"
    . "${ECFS_SYS_PATH}/.ecfs_bash_functions"
    . "${ECFS_SYS_PATH}/.ecfs_bash_aliases"
    ;;
  c[12]* )
    ;;
  cc* )
    PATH=$PATH:/usr/local/apps/ecfs/2.0.13rc2/bin
    ;;
  * )
    err "$prog - ERROR - ecfs not supported on this host ..."
    errit 1 ;;
esac

# test task:
case ${task} in

  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # list file or directory
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  'list' )

    # extract options
    els_options=''
    for option in ${options} ; do
      case ${option} in
        -l | --long  ) els_options="${els_options} -l" ;;
        -* )
          err "$prog - unknown option '${option}' for task '${task}'"
          errit 1
          ;;
      esac
    done
    
    # extract source and destination filespec:
    filespec=''
    for spec in ${filespecs} ; do 
      EvalSpecials ${spec}
      if [ -z "${filespec}" ]; then
        filespec=${FS}
      else
        err "$prog - ERROR - task '${task}' requires single file specification only."
        errit 1
      fi
    done
    if [ -z "${filespec}" ]; then
      err "$prog - ERROR - tasks '${task}' requires file specification."
      errit 1
    fi

    # list files:
    els ${els_options} ${filespec}
  
    ;;

  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # copy files
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  'get' )

    # extract options
    ecp_options=''
    do_mkdir=''
    for option in ${options} ; do
      case ${option} in
        -f | --force ) ecp_options="${ecp_options} -o" ;;
        -m | --mkdir ) do_mkdir='true' ;;
        -* )
          err "$prog - unknown option '${option}' for task '${task}'"
          errit 1
          ;;
      esac
    done

    # extract source and destination filespec:
    source_spec=''
    dest_spec=''
    for spec in ${filespecs} ; do 
      EvalSpecials ${spec}
      if [ -z "${source_spec}" ]; then
        source_spec=${FS}
      elif [ -z "${dest_spec}" ]; then
        dest_spec=${FS}
      else
        err "$prog - ERROR - task '${task}' requires source and destination file specifications only."
        errit 1
      fi
    done
    if [ -z "${dest_spec}" ]; then
      err "$prog - ERROR - task '${task}' requires source and destination file specifications."
      errit 1
    fi
    
    # create destination directory ?
    #  o destination is an existing file : not necessary
    #  o destination is an existing directory : not necessary 
    if [ ${do_mkdir} ] && [ ! -f ${dest_spec} ] && [ ! -d ${dest_spec} ]; then
      # destination is not an existing file or directory;
      # create the directory part of the destination:
      dest_dir=`/usr/bin/dirname ${dest_spec}`
      test "${dest_dir}" != "."  &&  /bin/mkdir -p ${dest_dir}
    fi
    
    # copy file; suppress error messages:
    outfile=".gss.out.$$"
    if ! ( ecp ${ecp_options} ec:${source_spec} ${dest_spec} > ${outfile} 2>&1 ) ; then
      /bin/cat ${outfile}
      /bin/rm -f ${outfile}
      err "$prog - ERROR from ecp"
      errit 1
    fi
    /bin/rm -f ${outfile}
  
    # get over the non working umask stuff -> default to 640
    chmod 640 ${dest_spec}
    

    ;;

  'put' )

    # defaults
    umask=022      # no write permissions for group and other

    # extract options
    ecp_options='-e'    # error if target already exists
    do_mkdir=''
    for option in ${options} ; do
      case ${option} in
        -f | --force ) ecp_options="-o" ;;
        -m | --mkdir ) do_mkdir='true' ;;
        -* )
          err "$prog - unknown option '${option}' for task '${task}'"
          errit 1
          ;;
      esac
    done

    # extract source and destination filespec:
    source_spec=''
    dest_spec=''
    for spec in ${filespecs} ; do 
      EvalSpecials ${spec}
      if [ -z "${source_spec}" ]; then
        source_spec=${FS}
      elif [ -z "${dest_spec}" ]; then
        dest_spec=${FS}
      else
        err "$prog - ERROR - task '${task}' requires source and destination file specifications only."
        errit 1
      fi
    done
    if [ -z "${dest_spec}" ]; then
      err "$prog - ERROR - task '${task}' requires source and destination file specifications."
      errit 1
    fi

    # set ECFS umask - do not exit if error (cca: not available, once in the queue)
    set +e
    eumask ${umask}
    set -e
    
    # create destination directory ?
    if [ ${do_mkdir} ]; then
      #  o destination is an existing file : not necessary
      #  o destination is an existing directory : not necessary 
      #if ! ${script} exist ${dest_spec} ; then
        # do not test if directory already exists,
        # this takes more time than just creation;
        # supress error messages about already existing directories ...
        dest_dir=`/usr/bin/dirname ${dest_spec}`
        outfile=".gss.out.$$"
        if ! ( emkdir -p ec:${dest_dir} > ${outfile} 2>&1 ) ; then
          /bin/cat ${outfile}
          /bin/rm -f ${outfile}
          err "$prog - ERROR from emkdir"
          errit 1
        fi
        /bin/rm -f ${outfile}
      #fi
    fi
    
    # copy file; suppress error messages:
    outfile=".gss.out.$$"
    if ! ( ecp ${ecp_options} ${source_spec} ec:${dest_spec} > ${outfile} 2>&1 ) ; then
      /bin/cat ${outfile}
      /bin/rm -f ${outfile}
      err "$prog - ERROR from ecp"
      errit 1
    fi
    /bin/rm -f ${outfile}
    
    # adhoc ...
    case "${umask}" in
      "022" ) echmod 644 ec:${dest_spec} ;;
      "002" ) echmod 664 ec:${dest_spec} ;;
    esac
  
    ;;

  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # task ???
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  * )
    err "$prog - ERROR - unsupported task '${task}'"
    errit 1
    ;;
  
esac  # tasks


# -------------------------------------------------------------
# --- end
# -------------------------------------------------------------

test ${verbose}  &&  echo "$prog - end"

# ok
exit 0