# shellcheck shell=bash
# ==========================================================================
#         _   _      _   ____            __ __  __      _
#        | \ | | ___| |_|  _ \ ___ _ __ / _|  \/  | ___| |_ ___ _ __
#        |  \| |/ _ \ __| |_) / _ \ '__| |_| |\/| |/ _ \ __/ _ \ '__|
#        | |\  |  __/ |_|  __/  __/ |  |  _| |  | |  __/ ||  __/ |
#        |_| \_|\___|\__|_|   \___|_|  |_| |_|  |_|\___|\__\___|_|
#
#                  NetPerfMeter -- Network Performance Meter
#                 Copyright (C) 2009-2026 by Thomas Dreibholz
# ==========================================================================
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact:  dreibh@simula.no
# Homepage: https://www.nntb.no/~dreibh/netperfmeter/


# ###### Bash completion for netperfmeter ###################################
_netperfmeter()
{
   # Based on:
   # * https://www.benningtons.net/index.php/bash-completion/
   # * /usr/share/bash-completion/completions/dd
   # * https://unix.stackexchange.com/questions/781584/complete-compgen-fails-to-suggest-when-options-contain-colon

   # This is necessary to properly handle ":" in completion words, in order
   # to properly handle IPv6 addresses!
   local COMP_WORDBREAKS="${COMP_WORDBREAKS//:}"

   local cur prev words cword
   if type -t _comp_initialize >/dev/null; then
      _comp_initialize || return
   elif type -t _init_completion >/dev/null; then
      _init_completion || return
   else
      # Manual initialization for older bash completion versions:
      COMPREPLY=()
      cur="${COMP_WORDS[COMP_CWORD]}"
      # shellcheck disable=SC2034
      prev="${COMP_WORDS[COMP_CWORD-1]}"
      # shellcheck disable=SC2034,SC2124
      words="${COMP_WORDS[@]}"
      # shellcheck disable=SC2034
      cword="${COMP_CWORD}"
   fi

   # echo "cur=${cur} prev=${prev} words=${words[@]} cword=${cword}"
   # echo ""

   # ====== Parameters ======================================================
   local flowSpec=0
   if [ "${cword}" -gt 1 ] ; then
      if [ "${prev}" == "--tcp" ]   || \
         [ "${prev}" == "--mptcp" ] || \
         [ "${prev}" == "--udp" ]   || \
         [ "${prev}" == "--dccp" ]  || \
         [ "${prev}" == "--sctp" ]  || \
         [ "${prev}" == "--quic" ] ; then
         flowSpec=1
      elif [[ "${prev}" =~ ^(const|exp|pareto|uniform) ]] ; then
         flowSpec=1
      fi

      if [ "${flowSpec}" -eq 1 ] ; then
         case "${cur}" in
            # ====== Flowspec ==================================================
            const*   | \
            exp*     | \
            pareto*  | \
            uniform*)
               # shellcheck disable=SC2155,SC2001
               local base="$(echo "${cur}" | sed -e 's/:[^:]*$/:/')"
               # shellcheck disable=SC2155,SC2001
               local blocks="$(echo "${base}" | tr -cd ":" | wc -c)"

               if [ "${blocks}" -lt 4 ] ; then
                  if [[ "${cur}" =~ (^|:)(const|exp|pareto|uniform)([0-9]+)$ ]] ; then
                     mapfile -t COMPREPLY < <(compgen -W "${cur}0 ${cur}1 ${cur}2 ${cur}3 ${cur}4 ${cur}5 ${cur}6 ${cur}7 ${cur}8 ${cur}9 ${cur}, ${cur}:" -- "${cur}")
                     compopt -o nospace
                     return
                  elif [[ "${cur}" =~ (^|:)(const|exp|pareto|uniform)$ ]] ; then
                     mapfile -t COMPREPLY < <(compgen -W "${cur}0 ${cur}1 ${cur}2 ${cur}3 ${cur}4 ${cur}5 ${cur}6 ${cur}7 ${cur}8 ${cur}9 ${cur}," -- "${cur}")
                     compopt -o nospace
                     return
                  else
                     mapfile -t COMPREPLY < <(compgen -W "${base}const ${base}exp ${base}pareto ${base}uniform" -- "${cur}" )
                     compopt -o nospace
                     return
                  fi
               else
                  mapfile -t COMPREPLY < <(compgen -W "
   ${base}cc=
   ${base}cmt=
   ${base}debug=
   ${base}defragtimeout=
   ${base}description=
   ${base}error_on_abort=
   ${base}id=
   ${base}maxmsgsize=
   ${base}nodelay=
   ${base}onoff=
   ${base}ordered=
   ${base}rcvbuf=
   ${base}reliable=
   ${base}rtx_timeout=
   ${base}rtx_trials=
   ${base}sndbuf=
   ${base}unordered=
   ${base}unreliable=
   ${base}v6only
   " -- "${cur}")
                  compopt -o nospace
                  return
               fi
               ;;
         esac
      fi

      case "${prev}" in
         #  ====== Generic value ============================================
         -A | --activenodename  | \
         -P | --passivenodename | \
         -o | --sndbuf          | \
         -i | --rcvbuf          | \
         -T | --runtime)
            return
            ;;
         # ====== Local address =============================================
         -L | --local | \
         -l | --controllocal)
            # Suggest local IP addresses:
            # NOTE: For IPv6, ":" must bave been removed from COMP_WORDBREAKS
            #       See comment above!
            local addresses
            if [ -x  /usr/sbin/ip ] ; then
               addresses="$( /usr/sbin/ip addr show | awk '/[ ]+inet/ { print $2 }' | sed -e 's#/.*$##')"
            elif [ -x /sbin/ifconfig ] ; then
               addresses="$(/sbin/ifconfig | awk '/[ \t]+inet/ { print $2 }' | sed -e 's#/.*$##')"
            fi
            mapfile -t COMPREPLY < <(compgen -W "${addresses}" -- "${cur}")
            return
            ;;
         # ====== Scalar/vector file pattern ================================
         -C | --config | \
         -S | --scalar | \
         -V | --vector)
            _filedir
            return
            ;;
         # ====== Special case: key file ====================================
         -K | --tls-key)
            _filedir '@(key)'
            return
            ;;
         # ====== Special case: certificate file ============================
         -I | --tls-ca | \
         -J | --tls-cert)
            _filedir '@(crt|pem)'
            return
            ;;
         # ====== Special case: hostname ====================================
         -H | --tls-hostname)
            mapfile -t COMPREPLY < <( compgen -W "$(hostname -f)" -- "${cur}" )
            return
            ;;
         # ====== Special case: log file ====================================
         --logappend | \
         --logfile)
            _filedir '@(log)'
            return
            ;;
         # ====== Special case: on/off ======================================
         --logcolor)
            mapfile -t COMPREPLY < <(compgen -W "on off" -- "${cur}")
            return
            ;;
      esac

   # ====== Port (passive side) or Address:Port (active side) ===============
   else
      mapfile -t COMPREPLY < <(compgen -W 'localhost:9000 9000' -- "$cur")
      return
   fi


   # ====== All options =====================================================
   local opts

   # ------ Active side -----------------------------------------------------
   # echo "cword=$cword D=${words[1]}"
   if [ "${cword}" -ge 2 ] && [[ ! "${words[1]}" =~ ^[0-9]+$ ]] ; then
      if [ ${flowSpec} -eq 0 ] ; then
         opts="
-x
--control-over-sctp
-y
--control-over-tcp
-w
--control-over-mptcp
-L
--local
-l
--controllocal
-H
--tls-hostname
-I
--tls-ca
--6
--v6only
--display
--nodisplay
-o
--sndbuf
-i
--rcvbuf
-T
--runtime
-C
--Ar
-S
--scalar
-V
--vector
-A
--activenodename
-P
--passivenodename
--loglevel
--logcolor
--logfile
--logappend
-t
--tcp
-m
--mptcp
-u
--udp
-d
--dccp
-s
--sctp
-k
--quic
-q
--quiet
-!
--verbose
-h
--help
-v
--version
"
      else
         opts="const exp pareto uniform"
      fi

   # ------ Passive side ----------------------------------------------------
   else
      opts="
-x
--control-over-sctp
-X
--no-control-over-sctp
-y
--control-over-tcp
-Y
--no-control-over-tcp
-w
--control-over-mptcp
-W
--no-control-over-tcp
-L
--local
-l
--controllocal
-K
--tls-key
-I
--tls-ca
-J
--tls-cert
--6
--v6only
--display
--nodisplay
--loglevel
--logcolor
--logfile
--logappend
-q
--quiet
-!
--verbose
"
   fi

   mapfile -t COMPREPLY < <(compgen -W "${opts}" -- "${cur}" )
   [ ${flowSpec} -eq 1  ] && compopt -o nospace
   return 0
}

complete -F _netperfmeter netperfmeter
