# casync(1) completion                               -*- shell-script -*-
# vim: et sts=4 sw=4

# SPDX-License-Identifier: LGPL-2.1+

# This function returns the n-th arg, excluding options
# @param $1 chars  Characters out of $COMP_WORDBREAKS which should
#     NOT be considered word breaks. See __reassemble_comp_words_by_ref.
# @param $2 glob   Options whose following argument should not be counted
# @param $3 glob   Options that should be counted as args
# @param $4 int    Number that define the n-th arg to return
__casync_get_arg_n()
{
    local i args cword words
    __reassemble_comp_words_by_ref "$1" words cword

    arg=
    args=1
    for (( i=1; i < cword; i++ )); do
        if [[ ${words[i]} != -* && ${words[i-1]} != $2 ||
              ${words[i]} == $3 ]]; then
            if [[ $args -eq $4 ]]; then
                arg=${words[i]}
                break
            fi
            (( args++ ))
        fi
    done
}

_casync() {
    # Assigned variable by _init_completion:
    #   cur    Current argument.
    #   prev   Previous argument.
    #   words  Argument array.
    #   cword  Argument array size.
    local cur prev words cword
    _init_completion -n = || return

    # Commands and options
    local cmds=(digest extract gc list make mkdev mount mtree stat)
    local opts=(-h --help --version)
    opts+=(-l --log-level)
    opts+=(-v --verbose)
    opts+=(-n --dry-run)
    opts+=(-c --cache-auto)
    opts+=(--store --extra-store --seed --cache)
    opts+=(--chunk-size --rate-limit-bps)
    opts+=(--with --without)
    opts+=(--what)
    opts+=(--exclude-nodump --exclude-submounts --exclude-file --undo-immutable --delete --punch-holes --reflink --hardlink --seed-output --mkdir --recursive)
    opts+=(--uid-shift --uid-range)
    opts+=(--digest)
    opts+=(--compression)
    local opts_arg="@(-l|--log-level|--store|--extra-store|--seed|--cache|--chunk-size|--rate-limit-bps|--with|--without|--what|--exclude-nodump|--exclude-submounts|--exclude-file|--undo-immutable|--delete|--punch-holes|--reflink|--hardlink|--seed-output|--recursive|--mkdir|--uid-shift|--uid-range|--digest|--compression)"

    case "$prev" in
        -l|--log-level)
            COMPREPLY=($(compgen -W "debug info err" -- "$cur"))
            return 0
            ;;
        --store|--extra-store|--seed|--cache)
            _filedir
            return 0
            ;;
        --chunk-size|--rate-limit-bps)
            return 0
            ;;
        --with|--without)
            COMPREPLY=($(compgen -W "best unix fat chattr fat-attrs privileged fuse 16bit-uids 32bit-uids user-names sec-time usec-time nsec-time 2sec-time read-only permissions symlinks device-nodes fifos sockets flag-hidden flag-system flag-archive flag-append flag-noatime flag-compr flag-nocow flag-nodump flag-dirsync flag-immutable flag-sync flag-nocomp flag-projinherit subvolume subvolume-ro xattrs acl selinux fcaps quota-projid" -- "$cur"))
            return 0
            ;;
        --what)
            COMPREPLY=($(compgen -W "archive archive-index blob blob-index directory help" -- "$cur"))
            return 0
            ;;
        --exclude-nodump|--exclude-submounts|--exclude-file|--undo-immutable|--delete|--punch-holes|--reflink|--hardlink|--seed-output|--recursive|--mkdir)
            COMPREPLY=($(compgen -W "1 yes y true t on 0 no n false f off" -- "$cur"))
            return 0
            ;;
        --uid-shift|--uid-range)
            return 0
            ;;
        --digest)
            COMPREPLY=($(compgen -W "sha256 sha512-256 default" -- "$cur"))
            return 0
            ;;
        --compression)
            COMPREPLY=($(compgen -W "xz gzip zstd default" -- "$cur"))
            return 0
            ;;
    esac

    # Check if a command was entered already
    local arg command
    __casync_get_arg_n ':=' "$opts_arg" '' 1
    command="$arg"

    # Completion per command
    if [[ -n $command ]]; then
        local args
        _count_args ':=' "$opts_arg" ''

        case "$command" in
            # make|extract [ARCHIVE|ARCHIVE_INDEX|DIRECTORY] [PATH]
            make|extract)
                if [[ $args -eq 2 ]]; then
                    _filedir '@(caibx|caidx|catar)'
                elif [[ $args -eq 3 ]]; then
                    _filedir
                fi
                ;;
            # list|mtree|stat [ARCHIVE|ARCHIVE_INDEX|DIRECTORY] [PATH]
            # mount [ARCHIVE|ARCHIVE_INDEX] PATH
            # mkdev [BLOB|BLOB_INDEX] [NODE]
            list|mtree|stat|mount|mkdev)
                if [[ $args -eq 2 ]]; then
                    _filedir
                elif [[ $args -eq 3 ]]; then
                    _filedir
                fi
                ;;
            # gc BLOB_INDEX|ARCHIVE_INDEX ...
            gc)
                _filedir '@(caibx|caidx)'
                ;;
            # digest [ARCHIVE|BLOB|ARCHIVE_INDEX|BLOB_INDEX|DIRECTORY]
            digest)
                if [[ $args -eq 2 ]]; then
                    _filedir
                fi
                ;;
            *)
                _filedir
                ;;
        esac

        COMPREPLY+=($(compgen -W "${opts[*]}" -- "$cur"))
        return 0
    fi

    # Initial completion
    case "$cur" in
        -*)
            COMPREPLY=($(compgen -W "${opts[*]}" -- "$cur"))
            return 0
            ;;
        *)
            COMPREPLY=($(compgen -W "${cmds[*]} ${opts[*]}" -- "$cur"))
            return 0
            ;;
    esac

} && \
complete -F _casync casync
