#compdef prt-get prt-cache

local curcontext="$curcontext" ret=1 _prt_get_current_install_root _prt_get_command state
local -a state_descr line _prt_get_current_global_args
local -A opt_args
local -a _commands _infooptions _diffoptions _depoptions _installoptions
local -a _sysupoptions _printfoptions _options

_commands=(
  help:'show this help'
  version:'show the current version'
  list:'show a list of available ports'
  printf:'print formatted list of available ports'
  listinst:'show a list of installed ports'
  listorphans:'list of ports with no packages depending on them'
  info:'show info about a port'
  path:'show path of a port'
  readme:'show a port'"'"'s readme file (if it exists)'
  dup:'find duplicate ports'
  isinst:'print whether ports are installed'
  current:'print installed version of port'
  diff:'list outdated packages (or check args for change)'
  quickdiff:'same as diff but simple format'
  depends:'show dependencies for these ports'
  quickdep:'same as depends but simple format'
  deptree:'show dependencies tree for <port>'
  dependent:'show installed packages which depend on '"'"'port'"'"''
  search:'show port names containing '"'"'expr'"'"''
  dsearch:'show ports containing '"'"'expr'"'"' in the name or description'
  fsearch:'show file names in footprints matching '"'"'pattern'"'"''
  install:'install ports'
  update:'update ports'
  grpinst:'install ports, stop on error'
  depinst:'install ports and their dependencies'
  remove:'remove ports'
  sysup:'update all outdated ports'
  lock:'lock current version of packages'
  unlock:'unlock packages'
  listlocked:'list locked packages'
  ls:'print a listing of the port'"'"'s directory'
  cat:'print out '"'"'port/file'"'"''
  edit:'edit '"'"'port/file'"'"''
)

# Options Information
_infooptions=(
  "--depsort[Sort by dependencies]"
)

# Options for Differences / Check for updates
_diffoptions=(
  "--all[display locked ports too]"
  "--prefer-higher[prefer higher installed versions over lower ports]"
  "--strict-diff[override prefer higher configuration setting]"
)

# Options for Dependencies
_depoptions=(
  "--all[list all dependent packages, not only installed]"
  "--recursive[print recursive listing]"
  "--tree[print recursive tree listing]"
)

# Options for Install, Update and Removal
_installoptions=(
  "-f[force installation]"
  "-fi[force installation]"
  "-fr[force rebuild]"
  "-uf[update footprint]"
  "-if[ignore footprint]"
  "-um[update md5sum]"
  "-im[ignore md5sum]"
  "-us[update signature]"
  "-is[ignore signature]"
  "--margs=[pass 'string' to pkgmk]"
  "--aargs=[pass 'string' to pkgadd]"
  "--rargs=[pass 'string' to pkgrm]"
  "--test[test mode]"
  "--log[write log file]"
  "--ignore=[Don't install/update those packages]:ignored packages:_sequence -s , _allports"
  "--pre-install[execute pre-install script]"
  "--post-install[execute post-install script]"
  "--install-scripts[execute pre-install and post-install script]"
)

# Options for System Update
_sysupoptions=(
  "--nodeps[don't sort by dependencies]"
  "--test[test mode]"
  "--log[write log file]"
  "--prefer-higher[prefer higher installed versions over lower ones in ports tree]"
  "--strict-diff[override prefer higher configuration setting]"
)

_printfoptions=(
  '%n[name]'
  '%p[path]'
  '%v[version]'
  '%r[release]'
  '%d[description]'
  '%e[dependencies]'
  '%u[URL]'
  '%P[Packager]'
  '%M[Maintainer]'
  '%R[Readme]'
  '%E[pre-install script]'
  '%O[post-install script]'
  '%l[is locked]'
  '%i[installed]'
)

# Options for General Options
_options=(
  "-v[Show version in listing]"
  "-vv[Show version and decription in listing]"
  "--path[Print path to port if appropriate (search, list, depends)]"
  "--cache[Use a cache file]"
  "--config=[Use alternative configuration file]:file:_files"
  "--install-root=[Use alternative install root directory]:directory:_directories"
  "--no-std-config[Don't parse default configuration file]"
  "--config-prepend=[Prepend '..' to configuration]:directory:_directories"
  "--config-append=[Append '..' to configuration]:directory:_directories"
  "--config-set=[Set configuration data '..', overriding config file]:data"
)

# Port list generators
_prt_get_global_args() {
  reply=()

  (( $+opt_args[--cache] )) && reply+=(--cache)
  (( $+opt_args[--no-std-config] )) && reply+=(--no-std-config)

  [[ -n ${opt_args[--config]} ]] &&
    reply+=(--config=${opt_args[--config]})
  [[ -n ${opt_args[--install-root]} ]] &&
    reply+=(--install-root=${opt_args[--install-root]})
  [[ -n ${opt_args[--config-prepend]} ]] &&
    reply+=(--config-prepend=${opt_args[--config-prepend]})
  [[ -n ${opt_args[--config-append]} ]] &&
    reply+=(--config-append=${opt_args[--config-append]})
  [[ -n ${opt_args[--config-set]} ]] &&
    reply+=(--config-set=${opt_args[--config-set]})
}

_prt_get_cached() {
  local cache_key cache_stamp db_path output
  local -a cmd

  typeset -gA _prt_get_completion_cache

  cache_stamp=$(command stat -c %Y /var/lib/pkg/prt-get.cache 2>/dev/null)
  db_path=${_prt_get_current_install_root:+${_prt_get_current_install_root%/}}/var/lib/pkg/db
  cache_stamp+=":$(command stat -c %Y "$db_path" 2>/dev/null)"
  cmd=(prt-cache "${_prt_get_current_global_args[@]}" "$@")
  cache_key="${cache_stamp}:${(j: :)${(qq)cmd}}"

  if (( $+_prt_get_completion_cache[$cache_key] )); then
    print -r -- ${_prt_get_completion_cache[$cache_key]}
    return 0
  fi

  output=$("${cmd[@]}" 2>/dev/null) || return 1
  _prt_get_completion_cache[$cache_key]=$output
  print -r -- $output
}

_allports() {
  local -a list
  list=(${(f)"$(_prt_get_cached list)"})
  _describe 'ports' list
}

_installedports() {
  local -a list
  list=(${(f)"$(_prt_get_cached listinst)"})
  _describe 'installedports' list
}

_notinstalledports() {
  local -a installed_ports all_ports not_installed_ports
  installed_ports=(${(f)"$(_prt_get_cached listinst)"})
  all_ports=(${(f)"$(_prt_get_cached list)"})
  not_installed_ports=(${all_ports:|installed_ports})

  _describe 'notinstalledports' not_installed_ports
}

_lockedports() {
  local -a list
  list=(${(f)"$(_prt_get_cached listlocked)"})
  _describe 'lockedports' list
}

_unlockedports() {
  local -a installed locked list
  installed=(${(f)"$(_prt_get_cached listinst)"})
  locked=(${(f)"$(_prt_get_cached listlocked)"})
  list=(${installed:|locked})

  _describe 'unlockedports' list
}

_outdatedports() {
  local -a list
  local quickdiff
  quickdiff=$(_prt_get_cached quickdiff)
  list=(${(o)${(z)quickdiff}})

  _describe 'outdatedports' list
}

_prt_get_diff_ports() {
  _alternative \
    'outdated ports:outdated port:_outdatedports' \
    'installed ports:installed port:_installedports'
}

_prt_get_port_files() {
  local -a list
  local port

  port=${line[1]}
  [[ $port == $_prt_get_command && -n ${line[2]} ]] && port=${line[2]}
  [[ -n $port ]] || return 1

  list=(${(f)"$(_prt_get_cached ls $port)"})
  (( $#list )) || return 1

  _describe 'port files' list
}

_prt_get_printf_formats() {
  _describe 'format specifiers' _printfoptions
}

_arguments -C \
  "${_options[@]}" \
  ":command:->command" \
  "*::argument:->argument" && ret=0

_prt_get_global_args
_prt_get_current_global_args=("${reply[@]}")
_prt_get_current_install_root=${opt_args[--install-root]}

# Command completion
case $state in
  command)
    _describe 'commands' _commands && ret=0
    ;;
  argument)
    _prt_get_command=${line[1]}
    curcontext="${curcontext%:*:*}:prt-get-${_prt_get_command}:"

    case $_prt_get_command in
      help | version | listorphans)
        # No options for help | version command
        ;;
      list)
        _arguments -S \
          ":filter pattern:" && ret=0
        ;;
      listinst)
        _arguments -S \
          "${_infooptions[@]}" \
          ":filter pattern:" && ret=0
        ;;
      printf)
        _arguments -S \
          "--sort=[sort by format string]:sort format:_prt_get_printf_formats" \
          "--filter=[filter ports]:filter pattern:" \
          ":format:_prt_get_printf_formats" && ret=0
        ;;
      info | path | readme | ls)
        _arguments \
          ":port:_allports" && ret=0
        ;;
      current)
        _arguments -S \
          ":installedports:_installedports" && ret=0
        ;;
      cat | edit)
        _arguments -C \
          ":port:_allports" \
          ":file:_prt_get_port_files" && ret=0
        ;;
      diff)
        _arguments -S \
          "${_diffoptions[@]}" \
          "*:port:_prt_get_diff_ports" && ret=0
        ;;
      quickdiff)
        # No Options for quickdiff
        ;;
      depends | quickdep | isinst)
        _arguments -S \
          "*:port:_allports" && ret=0
        ;;
      dependent)
        _arguments -S \
          "${_depoptions[@]}" \
          ":port:_allports" && ret=0
        ;;
      deptree)
        _arguments \
          ":port:_allports" && ret=0
        ;;
      dup | listlocked)
        # No arguments for dup and listlocked commands
        ;;
      search | dsearch)
        _arguments \
          ":expression:" && ret=0
        ;;
      fsearch)
        _arguments \
          ":pattern:" && ret=0
        ;;
      update)
        _arguments -S \
          "${_installoptions[@]}" \
          "*:port:_prt_get_diff_ports" && ret=0
        ;;
      remove)
        _arguments -S \
          "${_installoptions[@]}" \
          "*:installedports:_installedports" && ret=0
        ;;
      install | grpinst | depinst)
        _arguments -S \
          "*:notinstalledports:_notinstalledports" \
          "${_installoptions[@]}" && ret=0
        ;;
      sysup)
        _arguments -S \
          "${_sysupoptions[@]}" && ret=0
        ;;
      lock)
        _arguments -S \
          "*:unlockedports:_unlockedports" && ret=0
        ;;
      unlock)
        _arguments -S \
          "*:lockedports:_lockedports" && ret=0
        ;;
      *)
        ;;
    esac
    ;;
esac

return ret
