# ip(8) completion                                         -*- shell-script -*-

_comp_cmd_ip__iproute2_etc()
{
    _comp_compgen -a split -- "$(_comp_awk '!/#/ { print $2 }' "/etc/iproute2/$1" \
        2>/dev/null)"
}

_comp_cmd_ip__netns()
{
    _comp_compgen_split -- "$(
        {
            ${1-ip} -c=never netns list 2>/dev/null || ${1-ip} netns list
        } | _comp_awk '{print $1}'
    )"
}

_comp_cmd_ip()
{
    local cur prev words cword comp_args
    _comp_initialize -- "$@" || return

    case $prev in
        -V | -Version | -rc | -rcvbuf | -l | -loops)
            return
            ;;
        -f | -family)
            _comp_compgen -- -W 'inet inet6 ipx dnet link'
            return
            ;;
        -b | -batch)
            _comp_compgen_filedir
            return
            ;;
        -n | -netns)
            _comp_cmd_ip__netns "$1"
            return
            ;;
        -force)
            _comp_compgen -- -W '-batch'
            return
            ;;
    esac

    local subcword cmd="" has_cmd="" subcmd=""
    for ((subcword = 1; subcword < cword; subcword++)); do
        [[ ${words[subcword]} == -b?(atch) ]] && return
        [[ $has_cmd ]] && subcmd=${words[subcword]} && break
        [[ ${words[subcword]} != -* &&
            ${words[subcword - 1]} != -@(f?(amily)|rc?(vbuf)) ]] &&
            cmd=${words[subcword]} has_cmd=set
    done

    if [[ ! $has_cmd ]]; then
        case $cur in
            -*)
                _comp_compgen -a help - <<<"$(
                    ((cword == 1)) && printf '%s\n' -force
                    {
                        "$1" -c=never help || "$1" help
                    } 2>&1 | command sed -e \
                        's/[{|}=]/\n/g' -e \
                        's/\[\([^]]\{1,\}\)\]/\1/g'
                )"
                ;;
            *)
                _comp_compgen_split -- "help $(
                    {
                        $1 -c=never help || $1 help
                    } 2>&1 | command sed -e \
                        '/OBJECT := /,/}/!d' -e \
                        's/.*{//' -e \
                        's/}.*//' -e \
                        's/|//g'
                )"
                ;;
        esac
        return
    fi

    [[ $subcmd == help ]] && return

    case $cmd in
        l | link)
            case $subcmd in
                add)
                    # TODO
                    ;;
                delete)
                    case $((cword - subcword)) in
                        1)
                            _comp_compgen_available_interfaces
                            ;;
                        2)
                            _comp_compgen -- -W 'type'
                            ;;
                        3)
                            [[ $prev == type ]] &&
                                _comp_compgen -- -W 'vlan veth vcan dummy ifb
                                    macvlan can'
                            ;;
                    esac
                    ;;
                set)
                    if ((cword - subcword == 1)); then
                        _comp_compgen_available_interfaces
                    else
                        case $prev in
                            arp | dynamic | multicast | allmulticast | promisc | \
                                trailers)
                                _comp_compgen -- -W 'on off'
                                ;;
                            txqueuelen | name | address | broadcast | mtu | netns | alias) ;;

                            *)
                                local c="arp dynamic multicast allmulticast
                                    promisc trailers txqueuelen name address
                                    broadcast mtu netns alias"
                                [[ $prev != @(up|down) ]] && c+=" up down"
                                _comp_compgen -- -W "$c"
                                ;;
                        esac
                    fi
                    ;;
                show)
                    if ((cword == subcword + 1)); then
                        _comp_compgen_available_interfaces
                        _comp_compgen -a -- -W 'dev group up'
                    elif [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                    elif [[ $prev == group ]]; then
                        _comp_cmd_ip__iproute2_etc group
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add delete set show'
                    ;;
            esac
            ;;

        a | addr | address)
            case $subcmd in
                add | change | replace)
                    if [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                    elif [[ $prev == scope ]]; then
                        _comp_cmd_ip__iproute2_etc rt_scopes
                    else
                        : # TODO
                    fi
                    ;;
                del)
                    if [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                    elif [[ $prev == scope ]]; then
                        _comp_cmd_ip__iproute2_etc rt_scopes
                    else
                        : # TODO
                    fi
                    ;;
                show | flush)
                    if ((cword == subcword + 1)); then
                        _comp_compgen_available_interfaces
                        _comp_compgen -a -- -W 'dev scope to label dynamic
                            permanent tentative deprecated dadfailed temporary
                            primary secondary up'
                    elif [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                    elif [[ $prev == scope ]]; then
                        _comp_cmd_ip__iproute2_etc rt_scopes
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add change replace del show
                            flush'
                    ;;
            esac
            ;;

        addrlabel)
            case $subcmd in
                list | add | del | flush)
                    if [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                    else
                        : # TODO
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help list add del flush'
                    ;;
            esac
            ;;

        r | route)
            case $subcmd in
                list | flush)
                    if [[ $prev == proto ]]; then
                        _comp_cmd_ip__iproute2_etc rt_protos
                    else
                        : # TODO
                    fi
                    ;;
                get)
                    # TODO
                    ;;
                a | add | d | del | change | append | r | replace)
                    if [[ $prev == via ]]; then
                        _comp_compgen_split -- "$(
                            {
                                $1 -c=never r 2>/dev/null || $1 r
                            } | command sed -ne \
                                's/.*via \([0-9.]*\).*/\1/p'
                        )"
                    elif [[ $prev == "$subcmd" ]]; then
                        _comp_compgen_split -- "table default $(
                            {
                                $1 -c=never r 2>/dev/null || $1 r
                            } | cut -d ' ' -f 1
                        )"
                    elif [[ $prev == dev ]]; then
                        _comp_compgen_available_interfaces -a
                    elif [[ $prev == table ]]; then
                        _comp_compgen -- -W 'local main default'
                    else
                        _comp_compgen -- -W 'via dev weight'
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help list flush get add del change
                            append replace'
                    ;;
            esac
            ;;

        rule)
            case $subcmd in
                add | del | list | lst)
                    case $prev in
                        from | to | tos | dsfield | fwmark | uidrange | ipproto | sport | \
                            dport | priority | protocol | suppress_prefixlength | \
                            suppress_ifgroup | realms | nat | goto) ;;

                        iif | oif)
                            _comp_compgen_available_interfaces -a
                            ;;
                        table | lookup)
                            _comp_compgen -- -W 'local main default'
                            ;;
                        *)
                            _comp_compgen -- -W 'from to tos dsfield fwmark
                                uidrange ipproto sport dport priority table
                                lookup protocol suppress_prefixlength
                                suppress_ifgroup realms nat goto iif oif not'
                            ;;
                    esac
                    ;;
                flush | save)
                    if [[ $prev == protocol ]]; then
                        :
                    else
                        _comp_compgen -- -W 'protocol'
                    fi
                    ;;
                restore | show) ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add del list flush save
                            restore show'
                    ;;
            esac
            ;;

        neigh)
            case $subcmd in
                add | del | change | replace)
                    # TODO
                    ;;
                show | flush)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add del change replace show
                            flush'
                    ;;
            esac
            ;;

        ntable)
            case $subcmd in
                change)
                    # TODO
                    ;;
                show)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help change show'
                    ;;
            esac
            ;;

        tunnel)
            case $subcmd in
                show) ;;

                add | change | del | prl | 6rd)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add change del show prl 6rd'
                    ;;
            esac
            ;;

        maddr)
            case $subcmd in
                add | del)
                    # TODO
                    ;;
                show)
                    if [[ $cword -eq $subcword+1 || $prev == dev ]]; then
                        _comp_compgen_available_interfaces
                        if [[ $prev != dev ]]; then
                            _comp_compgen -a -W dev
                        fi
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add del show'
                    ;;
            esac
            ;;

        mroute)
            case $subcmd in
                show)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help show'
                    ;;
            esac
            ;;

        monitor)
            case $subcmd in
                all) ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen_split -- "help all $(
                            {
                                "$1" -c=never monitor help || "$1" monitor help
                            } 2>&1 | command sed -e \
                                '/OBJECTS := /,/[^|]$/!d' -e \
                                's/OBJECTS := *//' -e \
                                's/|//g'
                        )"
                    ;;
            esac
            ;;

        netns)
            case $subcmd in
                list | monitor) ;;

                add | identify | list-id)
                    # TODO
                    ;;
                delete | exec | pids | set)
                    [[ $prev == "$subcmd" ]] && _comp_cmd_ip__netns "$1"
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'help add delete exec identify list
                            list-id monitor pids set'
                    ;;
            esac
            ;;

        xfrm)
            case $subcmd in
                state | policy | monitor)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        _comp_compgen -- -W 'state policy monitor'
                    ;;
            esac
            ;;
    esac
} &&
    complete -F _comp_cmd_ip ip

# ex: filetype=sh
