#compdef lb-run run

###############################################################################
# (c) Copyright 2020 CERN                                                     #
#                                                                             #
# This software is distributed under the terms of the GNU General Public      #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
#                                                                             #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization  #
# or submit itself to any jurisdiction.                                       #
###############################################################################

# Usage: lb-run [OPTION]... [NAME=VALUE]... PROJECT[/VERSION] [COMMAND [ARG]...]
# Usage: xenv|./run [OPTION]... [NAME=VALUE]... [COMMAND [ARG]...]

integer NORMARG

# TODO: avoid duplication with _lb-dev
__projects () {
  local -a keys
  keys=(${(k)opt_args})
  # if --path-to-project is set, then ditch all this and use _files -/
  if (($keys[(Ie)--path-to-project])); then
    _files -/
    return 0
  fi
  if compset -P 1 '*/'; then
    # TODO: it appears lb-dev --nightly <SLOT> --list <PROJECT> does not list HEAD
    local -a versionlist
    project=${(S)IPREFIX#/}
    # TODO: this line differs from _lb-dev: strip off --runtime-project= from $project when completing --runtime-project=<Project>/<TAB>
    project=${project##*=}
    # (f) calling a subshell and splitting on line break https://unix.stackexchange.com/a/460798
    # [@] for every array element
    # %%\ *  remove everything with trailing ' *' (largest match)
    versionlist=(${${(f)"$(lb-run $words[2,-2] --list --quiet $project)"}[@]%%\ *})
    compadd "$@" ${versionlist}
  else
    # TODO: avoid duplication with _git-lb-use
    local -a projects
    projects=($(lb-completion-helper list_projects 2> /dev/null))
    if [[ $? -ne 0 ]]; then
      _message "could not determine list of projects, falling back to hard coded list"
      projects=(Gaudi LHCb Lbcom Rec Boole Brunel Gauss Phys Analysis Hlt Alignment Moore Online Euler Geant4 DaVinci Bender Orwell Panoramix LbScripts Dirac LHCbGrid Panoptes Curie Vetra VetraTB Compat VanDerMeer Ganga LHCbDirac Integration Erasmus Feicim Stripping LHCbExternals Urania VMDirac LHCbVMDirac Noether Tesla MooreOnline BeautyDirac Kepler AlignmentOnline Lovell L0MuonTools Calibration)
    fi
    compadd "$@" -S '/' ${projects}
  fi
}

# TODO: avoid duplication with _lb-set-platform (the version here adds best)
__lb-platforms() {
local -a compatible_platforms
compatible_platforms=($(lb-completion-helper list_compatible_platforms 2>/dev/null))
compatible_platforms+=(best)
compadd "$@" ${compatible_platforms[@]}
}

__nightly-slots() {
local -a nightly_bases
nightly_bases=()
if (( ${+LHCBNIGHTLIES} )); then
  nightly_bases+=${(s,:,)LHCBNIGHTLIES}
fi
if (( ${+LCG_nightlies_area} )); then
  nightly_bases+=${(s,:,)LCG_nightlies_area}
fi
[[ -d /cvmfs/lhcbdev.cern.ch/nightlies ]] && nightly_bases+=(/cvmfs/lhcbdev.cern.ch/nightlies)
[[ -n $opt_args[--nightly-base] ]] && nightly_bases+=($opt_args[--nightly-base])

  # bodge based on https://unix.stackexchange.com/a/572410
  for path in $nightly_bases; do
    if compset -P 1 '*/'; then
      _files -W $path/$IPREFIX -/ -S " " -F "*/*"
    else
      _files -W $path -/ -S "/"
    fi

  done
}

__envmanip() {
  # compset operates on PREFIX, this resolves '-s <PREFIX>' and
  # '--set=<PREFIX>' such that one doesn't need to handle a potential '='
  # before the parameter. the 1 is to make sure that the pattern NAME=VALUE is
  # correctly matched even if VALUE contains '='.

  local oldiprefix
  oldiprefix=${IPREFIX}
  
  if compset -P 1 '*='; then
    local parametername
    parametername=${${IPREFIX#${oldiprefix}}%=}
    _dispatch $service -value-,$parametername,-default-
  else
    _parameters -S '='
  fi
}

# TODO: use=, ext=, container=, grid-override-map= do not complete their arguments
local -a args
args=(
  '(- 1)'{-h,--help}'[Show help message]' \
  '(-v --verbose -q --quiet -d --debug)'{-d,--debug}'[be very verbose]'
  '(-v --verbose -q --quiet -d --debug)'{-v,--verbose}'[be more verbose]'
  '(-q --quiet -v --verbose -d --debug)'{-q,--quiet}'[be more quiet]'
  '(-i --ignore-environment)'{-i,--ignore-environment}'[start with an empty environment]'
  '(--sh --csh --py)--sh[Print the changes to the environment as "sh" shell commands]'
  '(--sh --csh --py)--csh[Print the changes to the environment as "csh" shell commands]'
  '(--sh --csh --py)--py[Print the changes to the environment as Python dictionary]'
  '(-A --all)'{-A,--all}'[Print all variables, instead of just the changes]'
  '(-u --unset)'{-u,--unset=}'[remove variable from the environment]:NAME: _parameters'
  '*'{-s,--set=}'[set the variable NAME to VALUE]:NAME=VALUE: __envmanip'
  '*'{-a,--append=}'[append VALUE to the variable NAME]:NAME=VALUE: __envmanip'
  '*'{-p,--prepend=}'[prepend VALUE to the variable NAME]:NAME=VALUE: __envmanip'
  '(-x --xml)'{-x,--xml=}'[XML file describing the changes to the environment]:XML: _files -g "*.xml"'
)
if [[ $service == lb-run ]]; then
  args+=(
  '(-c --platform)'{-c,--platform}'[runtime platform]:PLATFORM: __lb-platforms'
  '--dev[prepend $LHCBDEV to the search path]'
  '--dev-dir[prepend a directory to the search path]:DEVDIR: _files -/'
  '--nightly-base[add the specified directory to the nightly builds search path]:NIGHTLY_BASES: _files -/'
  '--nightly[Add the required slot of the LHCb nightly builds to the list of DEV dirs ]:SLOT[/(DAY|id)]: __nightly-slots'
  '(- 1)--help-nightly-local[Print instructions on how to install locally and use a nightly slot build]'
  '(--no-user-area --user-area)--user-area=[Use the specified path as User_release_area]:USER_AREA: _files -/'
  '(--no-user-area --user-area)--no-user-area[Ignore the user release area when looking for projects]'
  '(-r --siteroot)'{-r,--siteroot}'[path to the installation root]:SITEROOT: _files -/'
  '(-l --list)'{-l,--list}'[list the available versions of the requested project]'
  '(-L --list-platforms)'{-L,--list-platforms}'[list the available platforms for the requested project/version]'
  '(--use-sp --no-sp)--use-sp[Force fallback on SetupProject]'
  '(--use-sp --no-sp)--no-sp[Prevent fallback on SetupProject]'
  '--force-platform[ignore platform compatibility check]'
  '--profile[Print some profile informations about the execution]'
  '(--allow-containers --disallow-containers --prefer-container)--allow-containers[Allow a container technology to be automatically chosen]'
  '(--allow-containers  --disallow-containers --prefer-container)--disallow-containers[Prevent falling back to running with a container]'
  '(--allow-containers  --disallow-containers --prefer-container)--prefer-container[Prefer running inside containers to natively]'
  '--use=[add a data package to the environment]:USE'
  '--ext=[add an external lcg tool environment]:EXT'
  '*--runtime-project=[Add a project to the runtime environment]:PROJECT[/VERSION]: __projects'
  '*--overriding-project=[Add a project to override packages]:PROJECT[/VERSION]: __projects'
  '--no-auto-override[Do not automatically prepend the projects]'
  '(--grid-override --no-grid-override)--grid-override[Override grid middleware versions]'
  '(--grid-override --no-grid-override)--no-grid-override[Prevent override grid middleware versions]'
  '--grid-override-map=[Use specific grid middleware override map]:GRID_OVERRIDE_MAP'
  '--container=[wrap the command to run in a container]:CONTAINER'
  '(: -)--version[display version information]'
  '--path-to-project[Interpret the first argument as path to a project top-level directory]'
  '1:PROJECT[/VERSION]: __projects'
  )
fi
args+=('*: :->command')

_arguments -n $args[@]



case $state in
  command)
    integer shiftwidth
    if [[ $service == lb-run ]]; then
      (( shiftwidth=$NORMARG ))
    else
      (( shiftwidth=$NORMARG - 1 ))
    fi
    shift $shiftwidth words
    (( CURRENT-=$shiftwidth ))
    if [ $CURRENT -eq 1 ]; then
      # a user add suggestions by setting
      # zstyle ':completion::*:*run::' fake-commands gaudirun.py bender db-tags
      if zstyle -a ":completion:${curcontext}:" fake-commands tmp; then
        _wanted lhcbcommands expl "commonly used LHCb commands" compadd -- $tmp
      # else
      #   local -a common_commands
      #   common_commands=(gaudirun.py dst-dump bender db-tags)
      #   _wanted lhcbcommands expl "commonly used LHCb commands" compadd -- $common_commands
      fi
    fi
    _normal
    ;;
esac
