# OpenIndiana beadm(1M) completion                          -*- shell-script -*-
# ------------------------------------------------------------------------------
# Copyright (c) 2017, Aurelien Larcher <aurelien@openindiana.org>
# Copyright (c) 2019, Michal Nowak <mnowak@startmail.com>

# Bash-completion does not handle custom wordbreaks so comma-separated values
# cannot be implemented without this.
COMP_WORDBREAKS="${COMP_WORDBREAKS//,},"

# BE name may contain ':', e.g. to delimit date. It needs to be removed from
# set of word separators, otherwise we are stuck half-way in BE name completion.
COMP_WORDBREAKS="${COMP_WORDBREAKS//:/}"

_beadm()
{
  local cur prev words cword line
  line="${COMP_LINE}"
  _init_completion -n : || return

  local cmds="activate create destroy list mount unmount umount rename rollback"
  local cmd_opts=""

  # Lookup for command
  local special i
  for (( i=1; i < $cword; i++ ))
  do
    if [[ ${words[i]} == @(activate|create|destroy|list|@(|u|un)mount|rename|rollback) ]]
    then
      special=${words[i]}
      break
    fi
  done

  if [[ -z "${special}" ]]
  then
    COMPREPLY=( $(compgen -W "${cmds}" -- "${cur}") )
    return
  else
    # Command options
    if [[ "${cur}" == -* ]]
    then
      case "${special}" in
        activate|rename|rollback)
          # beadm activate [-v] beName
          # beadm rename [-v] origBeName newBeName
          # beadm rollback [-v] beName snapshot
          # beadm rollback [-v] beName@snapshot
          # Prevent recurring autocompletion
          if [[ "${prev}" != "-v" ]]; then cmd_opts="-v"; fi
          ;;
        create)
          # beadm create [-a] [-d BE_desc]
          #   [-o property=value] ... [-p zpool]
          #   [-e nonActiveBe | beName@snapshot] [-v] beName
          # beadm create [-d BE_desc]
          #   [-o property=value] ... [-p zpool] [-v] beName@snapshot
          cmd_opts="-a -d -o -p -e -v"
          ;;
        destroy)
          # beadm destroy [-Ffsv] beName
          # beadm destroy [-Fv] beName@snapshot
          cmd_opts="-F -f -s -v"
          ;;
        list)
          # beadm list [[-a] | [-d] [-s]] [-H]
          #   [-k|-K date | name | space] [-v] [beName]
          cmd_opts="-a -d -s -H -k -K -v"
          ;;
        mount)
          # beadm mount [-s ro|rw] [-v] beName [mountpoint]
          cmd_opts="-s -v"
          ;;
        unmount|umount)
          # beadm unmount [-fv] beName | mountpoint
          # beadm umount [-fv] beName | mountpoint
          cmd_opts="-f -v"
          ;;
        *)
          ;;
      esac
      COMPREPLY=( $(compgen -W "${cmd_opts}" -- "${cur}") )
      return
    else
      case "${special}" in
        activate|destroy|*mount|rename|rollback)
          # beadm activate [-v] beName
          # beadm destroy [-Ffsv] beName
          # beadm destroy [-Fv] beName@snapshot
          # beadm rename [-v] origBeName newBeName
          # beadm rollback [-v] beName snapshot
          # beadm rollback [-v] beName@snapshot
          case "${prev}" in
            -s)
              # Only for mount
              if [[ "${special}" == "mount" ]]
              then
                COMPREPLY=( $(compgen -W "ro rw" -- "${cur}") )
                return
              fi
              ;;
            *)
              case "${cur}" in
                *@)
                  compopt -o nospace
                  COMPREPLY=( $(compgen -W "$(beadm list -H -s | nawk -F ';' '{print $2}')" -- "${cur}") )
                  return
                  ;;
                *)
                  local be_filter=""
                  local be_and_snapshots=()
                  case "${special}" in
                    activate)
                      # Activate only BEs not already set active on reboot ('R')
                      be_and_snapshots=( $(beadm list -H | nawk -F ';' '$3 !~ "R"  {print $1}') )
                      ;;
                    destroy)
                      be_and_snapshots=( $(beadm list -H -a | nawk -F ';' '$2 ~ "@" {print $2}; $3 !~ "N" {print $1}' | sort | uniq) )
                      ;;
                    mount)
                      be_and_snapshots=( $(beadm list -H | nawk -F ';' '$3 !~ "N" && $4 == "" {print $1}') )
                      ;;
                    umount|unmount)
                      be_and_snapshots=( $(beadm list -H | nawk -F ';' '$3 !~ "N" && $4 != "" {print $1}') )
                      ;;
                    rename)
                      # Rename all but currently/now active ('N') BEs
                      be_and_snapshots=( $(beadm list -H | nawk -F ';' '$3 !~ "N"  {print $1}') )
                      ;;
                    rollback)
                      # list BEs and snapshots
                      be_and_snapshots=( $(beadm list -H -a | nawk -F ';' '$2 ~ "@" {print $2}; $3 !~ "N" {print $1}' | sort | uniq) )
                      case "${line}" in
                        *@*)
                          # entered BE@snapshot, hence we are done here
                          return
                          ;;
                        *)
                          # entered BE name, so find snapshot for the particuler BE
                          if [[ "${prev}" != "rollback" ]]
                          then
                            be_and_snapshots=( $(for K in echo "${!be_and_snapshots[@]}"; do echo ${be_and_snapshots[$K]} | grep "^${prev}@" | sed -e 's,.*@,,'; done) )
                          fi
                          ;;
                      esac
                  esac
                  compopt -o nospace
                  COMPREPLY=( $(compgen -W "${be_and_snapshots[*]}" -- "${cur}") )
                  return
                  ;;
              esac
              ;;
          esac
          ;;
        create)
          # beadm create [-a] [-d BE_desc]
          #   [-o property=value] ... [-p zpool]
          #   [-e nonActiveBe | beName@snapshot] [-v] beName
          # beadm create [-d BE_desc]
          #   [-o property=value] ... [-p zpool] [-v] beName@snapshot
          case "${prev}" in
            -p)
              COMPREPLY=( $(compgen -W "$(zpool list -H -o name)" -- "${cur}") )
              return
              ;;
            -e)
              case "${cur}" in
                *@)
                  compopt -o nospace
                  COMPREPLY=( $(compgen -W "$(beadm list -H -s | nawk -F ';' '{print $2}')" -- "${cur}") )
                  return
                  ;;
                *)
                  be_and_snapshots=( $(beadm list -H -a | nawk -F ';' '$2 ~ "@" {print $2}; $3 !~ "N" {print $1}' | sort | uniq) )
                  compopt -o nospace
                  COMPREPLY=( $(compgen -W "${be_and_snapshots[*]}" -- "${cur}") )
                  return
                  ;;
              esac
              ;;
            -o|,)
              # ZFS property
              compopt -o nospace
              COMPREPLY=( $(compgen -W "$(zfs get 2>&1 | nawk '$2 == "YES" {print $1}')" -S '=' -- "${cur}") )
              return
              ;;
            =)
              # ZFS property value
              local pprev="${COMP_WORDS[COMP_CWORD-2]}"
              local realcur="${cur##*=}"
              local zfsprop="${pprev%%@*}"; zfsprop="${zfsprop##*,}"
              local zfsvals=( $(zfs get 2>&1 | nawk '$1 == "'${zfsprop}'" && $2 == "YES" { $1=""; $2=""; $3=""; print }' | sed -e 's,|,,g') )
              compopt -o nospace
              compopt -o nosort
              COMPREPLY=( $(compgen -W "${zfsvals[*]}" -- "${realcur}") )
              ;;
            *)
              case "${cur}" in
                ,*)
                  # ZFS property after comma
                  local realcur=${cur##*,}
                  compopt -o nospace
                  COMPREPLY=( $(compgen -W "$(zfs get 2>&1 | nawk '$2 == "YES" {print $1}')" -S '=' -- "${realcur}") )
                  return
                  ;;
                =)
                  # ZFS property values
                  local realcur=${cur##*=}
                  local zfsprop=${prev%%@*}; zfsprop=${zfsprop##*,}
                  local zfsvals=( $(zfs get 2>&1 | nawk '$1 == "'${zfsprop}'" && $2 == "YES" { $1=""; $2=""; $3=""; print }' | sed -e 's,|,,g') )
                  compopt -o nospace
                  compopt -o nosort
                  COMPREPLY=( $(compgen -W "${zfsvals[*]}" -- "${realcur}") )
                  return
                  ;;
              esac
              ;;
          esac
          ;;
        list)
          # beadm list [[-a] | [-d] [-s]] [-H]
          #   [-k|-K date | name | space] [-v] [beName]
          case "${prev}" in
            -k|-K)
              COMPREPLY=( $(compgen -W "date name space" -- "${cur}") )
              return
              ;;
            *)
              local be_list=( $(beadm list -H | nawk -F ';' '{print $1}') )
              compopt -o nospace
              COMPREPLY=( $(compgen -W "${be_list[*]}" -- "${cur}") )
              ;;
          esac
          ;;
        *)
          ;;
      esac
    fi
  fi
} &&
  complete -F _beadm +o default beadm

# ex: filetype=sh
# vim: tabstop=2 shiftwidth=2 expandtab smartindent
