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

_iproute2_etc()
{
    COMPREPLY+=($(compgen -W \
        "$(awk '!/#/ { print $2 }' /etc/iproute2/$1 2>/dev/null)" \
        -- "$cur"))
}

_ip()
{
    local cur prev words cword
    _init_completion || return

    case $prev in
        -V | -Version | -rc | -rcvbuf)
            return
            ;;
        -f | -family)
            COMPREPLY=($(compgen -W 'inet inet6 ipx dnet link' -- "$cur"))
            return
            ;;
        -b | -batch)
            _filedir
            return
            ;;
        -force)
            COMPREPLY=($(compgen -W '-batch' -- "$cur"))
            return
            ;;
    esac

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

    if [[ ! -v cmd ]]; then
        case $cur in
            -*)
                local c="-Version -statistics -details -resolve -family
                    -oneline -timestamp -batch -rcvbuf"
                ((cword == 1)) && c+=" -force"
                COMPREPLY=($(compgen -W "$c" -- "$cur"))
                ;;
            *)
                COMPREPLY=($(compgen -W "help $($1 help 2>&1 | command sed -e \
                    '/OBJECT := /,/}/!d' -e \
                    's/.*{//' -e \
                    's/}.*//' -e \
                    's/|//g')" -- "$cur"))
                ;;
        esac
        return
    fi

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

    case $cmd in
        l | link)
            case $subcmd in
                add)
                    # TODO
                    ;;
                delete)
                    case $((cword - subcword)) in
                        1)
                            _available_interfaces
                            ;;
                        2)
                            COMPREPLY=($(compgen -W 'type' -- "$cur"))
                            ;;
                        3)
                            [[ $prev == type ]] &&
                                COMPREPLY=($(compgen -W 'vlan veth vcan dummy
                                    ifb macvlan can' -- "$cur"))
                            ;;
                    esac
                    ;;
                set)
                    if ((cword - subcword == 1)); then
                        _available_interfaces
                    else
                        case $prev in
                            arp | dynamic | multicast | allmulticast | promisc | \
                                trailers)
                                COMPREPLY=($(compgen -W 'on off' -- "$cur"))
                                ;;
                            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"
                                COMPREPLY=($(compgen -W "$c" -- "$cur"))
                                ;;
                        esac
                    fi
                    ;;
                show)
                    if ((cword == subcword + 1)); then
                        _available_interfaces
                        COMPREPLY+=($(compgen -W 'dev group up' -- "$cur"))
                    elif [[ $prev == dev ]]; then
                        _available_interfaces
                    elif [[ $prev == group ]]; then
                        _iproute2_etc group
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help add delete set show' \
                            -- "$cur"))
                    ;;
            esac
            ;;

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

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

        r | route)
            case $subcmd in
                list | flush)
                    if [[ $prev == proto ]]; then
                        _iproute2_etc rt_protos
                    else
                        : # TODO
                    fi
                    ;;
                get)
                    # TODO
                    ;;
                a | add | d | del | change | append | r | replace | monitor)
                    if [[ $prev == via ]]; then
                        COMPREPLY=($(compgen -W "$($1 r | command sed -ne \
                            's/.*via \([0-9.]*\).*/\1/p')" -- "$cur"))
                    elif [[ $prev == "$subcmd" ]]; then
                        COMPREPLY=($(compgen -W "table default \
                            $($1 r | cut -d ' ' -f 1)" -- "$cur"))
                    elif [[ $prev == dev ]]; then
                        _available_interfaces -a
                    elif [[ $prev == table ]]; then
                        COMPREPLY=($(compgen -W 'local main default' -- "$cur"))
                    else
                        COMPREPLY=($(compgen -W 'via dev weight' -- "$cur"))
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help list flush get add del
                            change append replace monitor' -- "$cur"))
                    ;;
            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)
                            _available_interfaces -a
                            ;;
                        table | lookup)
                            COMPREPLY=($(compgen -W 'local main default' -- "$cur"))
                            ;;
                        *)
                            COMPREPLY=($(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' -- "$cur"))
                            ;;
                    esac
                    ;;
                flush | save)
                    if [[ $prev == protocol ]]; then
                        :
                    else
                        COMPREPLY=($(compgen -W 'protocol' -- "$cur"))
                    fi
                    ;;
                restore | show) ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help add del list flush save
                            restore show' -- "$cur"))
                    ;;
            esac
            ;;

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

        ntable)
            case $subcmd in
                change)
                    # TODO
                    ;;
                show)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help change show' \
                            -- "$cur"))
                    ;;
            esac
            ;;

        tunnel)
            case $subcmd in
                show) ;;

                add | change | del | prl | 6rd)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help add change del show prl
                            6rd' -- "$cur"))
                    ;;
            esac
            ;;

        maddr)
            case $subcmd in
                add | del)
                    # TODO
                    ;;
                show)
                    if [[ $cword -eq $subcword+1 || $prev == dev ]]; then
                        _available_interfaces
                        [[ $prev != dev ]] &&
                            COMPREPLY=($(compgen -W '${COMPREPLY[@]} dev' \
                                -- "$cur"))
                    fi
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help add del show' \
                            -- "$cur"))
                    ;;
            esac
            ;;

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

        monitor)
            case $subcmd in
                all) ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'help all' -- "$cur"))
                    ;;
            esac
            ;;

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

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

        xfrm)
            case $subcmd in
                state | policy | monitor)
                    # TODO
                    ;;
                *)
                    ((cword == subcword)) &&
                        COMPREPLY=($(compgen -W 'state policy monitor' \
                            -- "$cur"))
                    ;;
            esac
            ;;
    esac
} &&
    complete -F _ip ip

# ex: filetype=sh
