#
#  Completion for ddiskit:
#

_ddiskit()
{
    #set -x

    COMPREPLY=()
    local cur prev words cword comp_replies
    _get_comp_words_by_ref -n = cur prev words cword

    local global_opts="-v -p -R -T -P -d -o -q -Q -C"
    local global_opts_long="--verbosity --profile --res-dir --template-dir --profile-dir --dump-config --dump-config-name --quilt-enable --quilt-disable --config-option"
    local prepare_sources_opts="-c -t"
    local prepare_sources_opts_long="--config --config-template"
    local generate_spec_opts="-c -t"
    local generate_spec_opts_long="--config --spec-template"
    local build_rpm_opts="-c -a -e -s -m -r -l -g"
    local build_rpm_opts_long="--config --tar-all --tar-strict --srpm --mock --mock-config --mock-offline --check-git-src"
    local build_iso_opts="-c -i"
    local build_iso_opts_long="--config --isofile"
    local dump_config_opts="-c -o"
    local dump_config_opts_long="--config --dump-config-name"
    local cmds="prepare_sources generate_spec build_rpm build_iso dump_config"
    local config="module.config"
    local config_options="
        config=
        config_template=
        dump_config=
        dump_config_name=
        isofile=
        isofile_mode=
        mock=
        mock_config=
        mock_offline=
        profile=
        profile_dir=
        quilt_series_dir=
        quilt_support=
        res_dir=
        spec_template=
        src_patterns=
        srpm=
        tar_all=
        tar_strict=
        template_dir=
        verbosity=
        defaults.config=
        defaults.config_template=
        defaults.dump_config=
        defaults.dump_config_name=
        defaults.isofile=
        defaults.isofile_mode=
        defaults.mock=
        defaults.mock_config=
        defaults.mock_offline=
        defaults.profile=
        defaults.profile_dir=
        defaults.quilt_series_dir=
        defaults.quilt_support=
        defaults.res_dir=
        defaults.spec_template=
        defaults.src_patterns=
        defaults.srpm=
        defaults.tar_all=
        defaults.tar_strict=
        defaults.template_dir=
        defaults.verbosity=
        global.include_srpm=
        global.module_author=
        global.module_author_email=
        global.module_vendor=
        spec_file.date=
        spec_file.dependencies=
        spec_file.firmware=
        spec_file.firmware_begin=
        spec_file.firmware_end=
        spec_file.firmware_files=
        spec_file.firmware_files_install=
        spec_file.firmware_include=
        spec_file.firmware_version=
        spec_file.kernel_arch=
        spec_file.kernel_requires=
        spec_file.kernel_version=
        spec_file.module_build_dir=
        spec_file.module_name=
        spec_file.module_requires=
        spec_file.module_rpm_release=
        spec_file.module_version=
        spec_file.rpm_dist=
        spec_file.source_patches=
        spec_file.source_patches_do="

    local profile_dir=/usr/share/ddiskit/profiles
    local template_dir=/usr/share/ddiskit/templates
    local mock_dir=/etc/mock

    # $w usually stores part of command-line argument which includes option and
    # its argument.
    # $w1 is $w with option stripped (just option argument).
    local i j w w1
    local cmd=""
    local cmd_idx=-1

    local before_skip
    local skip=0

    # $1 - list of options to skip
    # $w1 contains $w with options stripped
    _ddiskit_strip_opts()
    {
            local _w="${w:1}"
            w1="${_w#[$1]}"

            # First, stripping options without arguments
            while [ "$_w" != "$w1" ];
            do
                _w="$w1"
                w1="${_w#[$1]}"
            done
    }

    # We need a hack similar to __ltrim_colon_completions, but for the equal
    # sign.
    _ddiskit_ltrim_eq_completions()
    {
        if [[ "$cur" == *=* && "$COMP_WORDBREAKS" == *=* ]]
        then
            local prefix="${cur%=*}="
            local i=${#COMPREPLY[*]}
            while [[ $((--i)) -ge 0 ]]; do
                COMPREPLY[$i]=${COMPREPLY[$i]#"$prefix"}
            done
        fi
    }

    # A big kludge needed for preserving trailing white space in the completion
    # options. Appends contents of comp_replies variables to COMPREPLY array,
    # one item per line.
    _ddiskit_comp_append()
    {
        # Early bailout in order to avoid adding single empty option
        [ -n "$comp_replies" ] || return 0

        local _ORIG_IFS="$IFS"
        IFS=''
        while read line
        do
            COMPREPLY+=("$line")
        done << EOF
$comp_replies
EOF
        IFS="$_ORIG_IFS"
    }

    # $1 - word
    # $2 - prefix
    _ddiskit_comp_dir()
    {
        comp_replies=$(cd `dirname "$config"`; compgen -d -S / -P "$2" -- "$1")
        _ddiskit_comp_append
        _ddiskit_ltrim_eq_completions
    }

    # $1 - word
    # $2 - prefix
    # $3 - this is config (resolve realtive to current dir and not ocnfig dir)
    # $4 - glob pattern
    _ddiskit_comp_file()
    {
        comp_replies=$([ "$3" != 1 ] && cd `dirname "$config"`; \
            grep -x -v -F -f <(compgen -d -P "$2" -S '$' -- "$1") \
                <(compgen -f  -P "$2" -S '$' -- "$1" | sed -n "/$4\$$/p") \
                | sed 's/\$$/ /'; \
            compgen -d -S / -P "$2" -- "$1")
        _ddiskit_comp_append
        _ddiskit_ltrim_eq_completions
    }

    # $1 - word
    # $2 - prefix
    # $3 - cfg dir
    # $4 - suffix
    _ddiskit_comp_cfg()
    {
        if [ "${1#*/*}" != "${1}" -o \( -n "$4" -a "${1%$4}" != "$1" \) ]
        then
            _ddiskit_comp_file "$1" "$2" 0 "$4"
        else
            comp_replies=$(compgen -P "$2" -W "`ls "$3" | sed -n /$4\$/s/$4\$//p`" -- "$1" | sed 's/$/ /')
            _ddiskit_comp_append
            _ddiskit_ltrim_eq_completions
        fi
    }

    # $1 - word
    # $2 - prefix
    _ddiskit_comp_cfg_opt()
    {
        if [ "${1#*=}" != "$1" ]
        then
            local _w="$2${1%%=*}="
            local _w1="${1#*=}"
            _ddiskit_comp_file "$_w1" "$_w" 0
        else
            comp_replies=$(compgen -o nospace -P "$2" -W "${config_options}" -- "$1" | sed 's/$/ /')
            _ddiskit_comp_append
            _ddiskit_ltrim_eq_completions
        fi
    }

    # $1 - word to complete
    # $2 - prefix
    # $@ - word list
    _ddiskit_comp_list()
    {
        local _w="$1"
        shift
        local _p="$1"
        shift

        comp_replies=$(compgen -P "$_p" -W "$*" -- "$_w" | sed 's/$/ /')
        _ddiskit_comp_append
        _ddiskit_ltrim_eq_completions
    }

    for i in $(seq 1 $((cword - 1)) )
    do
        w="${words[$i]}"

        if [ "$skip" = 1 ]
        then
            [ "$before_skip" = "-P" ] && profile_dir="$w"
            [ "$before_skip" = "-T" ] && template_dir="$w"

            skip=0
            continue
        fi

        # Skipping word if previous word is an option which requires parameter.
        case "$w" in
        --template-dir=*)
            template_dir=${w#--template-dir=}
            continue
            ;;
        --profile-dir=*)
            profile_dir=${w#--profile-dir=}
            continue
            ;;
        --profile=*|--res-dir=*|--dump-config-name=*|--config-option=*)
            continue
            ;;
        --profile|--res-dir|--template-dir|--profile-dir|--dump-config-name|--config-option)
            [ "$w" = "--profile-dir" ] && before_skip="-P"
            [ "$w" = "--template-dir" ] && before_skip="-T"
            skip=1
            continue
            ;;
        -[vpRTPdoqQC]*)
            _ddiskit_strip_opts vdqQ

            # Then, checking whether the rest is option which requires argument
            # and it is the last character left
            if [ "${#w1}" = 1 -a "${w1#[pRTPoC]}" != "$w1" ]
            then
                before_skip="-$w1"
                skip=1

                [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
            fi

            continue
            ;;
        esac

        for j in $cmds
        do
            if [ "${words[$i]}" = "$j" ]
            then
                cmd=$j
                cmd_idx=$i
                break
            fi
        done

        [ -n "$cmd" ] && break
    done

    # Handle the case no command provided yet
    if [ -z "$cmd" ]
    then
        [ "$skip" = 1 ] && case "$prev" in
        -o|--dump-config-name)
            _ddiskit_comp_file "$cur"
            return 0
            ;;
        -R|-P|-T|--res-dir|--profile-dir|--template-dir)
            _ddiskit_comp_dir "$cur"
            return 0
            ;;
        -p|--profile)
            _ddiskit_comp_cfg "$cur" "" "$profile_dir"
            return 0
            ;;
        -C|--config-option)
            _ddiskit_comp_cfg_opt "$cur"
            return 0
            ;;
        esac

        case "$cur" in
        --dump-file-name=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}="
            return 0
            ;;
        --profile-dir=*|--template-dir=*|--res-dir=*)
            _ddiskit_comp_dir "${cur#--*=}" "${cur%%=*}="
            return 0
            ;;
        --profile=*)
            _ddiskit_comp_cfg "${cur#--*=}" "${cur%%=*}=" "$profile_dir"
            return 0
            ;;
        --config-option=*)
            _ddiskit_comp_cfg_opt "${cur#--config-option=}" "--config-option="
            return 0
            ;;

        -[vpRTPdoqQC]*)
            w="$cur"
            _ddiskit_strip_opts vdqQ

            w="$w1"
            w1="${w:1}"

            case "$w" in
            o*)
                _ddiskit_comp_file "$w1" "${cur%$w1}"
                return 0
                ;;
            P*|R*|T*)
                _ddiskit_comp_dir "$w1" "${cur%$w1}"
                return 0
                ;;
            p*)
                _ddiskit_comp_cfg "$w1" "${cur%$w1}" "$profile_dir"
                return 0
                ;;
            C*)
                _ddiskit_comp_cfg_opt "$w1" "${cur%$w1}"
                return 0
                ;;
            esac
        ;;
        esac

        # Modern bash has -o nosort, but it is not present even in the version
        # shipped in Fedora 25, so we should probably avoid adding it for now.
        _ddiskit_comp_list "$cur" "" "${global_opts} ${global_opts_long} ${cmds}"
        return 0
    fi

    skip=0

    case "${cmd}" in
    prepare_sources)
        for i in $(seq "$cmd_idx" $((cword - 1)) )
        do
            w="${words[$i]}"

            if [ "$skip" = 1 ]
            then
                [ "$before_skip" = "-c" ] && config="$w"

                skip=0
                continue
            fi

            case "$w" in
            --config|--config-template)
                [ "$w" = "--config" ] && before_skip="-c"
                skip=1
                continue
                ;;
            -[ct]*)
                w1="${w:1}"

                if [ "${#w1}" = 1 -a "${w1#[ct]}" != "$w1" ]
                then
                    before_skip="-$w1"
                    skip=1

                    [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
                fi

                continue
                ;;
            esac
        done

        [ "$skip" = 1 ] && case "$prev" in
        -c|--config)
            _ddiskit_comp_file "$cur" "" 1
            return 0
            ;;
        -t|--config-template)
            _ddiskit_comp_cfg "$cur" "" "$template_dir"
            return 0
            ;;
        esac

        case "$cur" in
        --config=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 1
            return 0
            ;;
        --config-template=*)
            _ddiskit_comp_cfg "${cur#--*=}" "${cur%%=*}=" "$template_dir"
            return 0
            ;;
        -[ct]*)
            w="${cur:1}"
            w1="${w:1}"

            case "$w" in
            c*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 1
                return 0
                ;;
            t*)
                _ddiskit_comp_cfg "$w1" "${cur%$w1}" "$template_dir"
                return 0
                ;;
            esac
        ;;
        esac

        _ddiskit_comp_list "$cur" "" "${prepare_sources_opts} ${prepare_sources_opts_long}"
        return 0
        ;;
    generate_spec)
        for i in $(seq "$cmd_idx" $((cword - 1)) )
        do
            w="${words[$i]}"

            if [ "$skip" = 1 ]
            then
                [ "$before_skip" = "-c" ] && config="$w"

                skip=0
                continue
            fi

            case "$w" in
            --config|--spec-template)
                [ "$w" = "--config" ] && before_skip="-c"
                skip=1
                continue
                ;;
            -[ct]*)
                w1="${w:1}"

                if [ "${#w1}" = 1 -a "${w1#[ct]}" != "$w1" ]
                then
                    before_skip="-$w1"
                    skip=1

                    [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
                fi

                continue
                ;;
            esac
        done

        [ "$skip" = 1 ] && case "$prev" in
        -c|--config)
            _ddiskit_comp_file "$cur" "" 1
            return 0
            ;;
        -t|--spec-template)
            _ddiskit_comp_cfg "$cur" "" "$template_dir"
            return 0
            ;;
        esac

        case "$cur" in
        --config=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 1
            return 0
            ;;
        --spec-template=*)
            _ddiskit_comp_cfg "${cur#--*=}" "${cur%%=*}=" "$template_dir"
            return 0
            ;;
        -[ct]*)
            w="${cur:1}"
            w1="${w:1}"

            case "$w" in
            c*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 1
                return 0
                ;;
            t*)
                _ddiskit_comp_cfg "$w1" "${cur%$w1}" "$template_dir"
                return 0
                ;;
            esac
        ;;
        esac

        _ddiskit_comp_list "$cur" "" "${generate_spec_opts} ${generate_spec_opts_long}"
        return 0
        ;;
    build_rpm)
        for i in $(seq "$cmd_idx" $((cword - 1)) )
        do
            w="${words[$i]}"

            if [ "$skip" = 1 ]
            then
                [ "$before_skip" = "-c" ] && config="$w"

                skip=0
                continue
            fi

            case "$w" in
            --config|--mock-config|--check-git-src)
                [ "$w" = "--config" ] && before_skip="-c"
                skip=1
                continue
                ;;
            -[caesmrlg]*)
                _ddiskit_strip_opts aesml

                if [ "${#w1}" = 1 -a "${w1#[crg]}" != "$w1" ]
                then
                    before_skip="-$w1"
                    skip=1

                    [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
                fi

                continue
                ;;
            esac
        done

        [ "$skip" = 1 ] && case "$prev" in
        -c|--config)
            _ddiskit_comp_file "$cur" "" 1
            return 0
            ;;
        -r|--mock-config)
            _ddiskit_comp_cfg "$cur" "" "$mock_dir" ".cfg"
            return 0
            ;;
        -g|--check-git-src)
            _ddiskit_comp_list "$cur" "" 0 1 2
            return 0
            ;;
        esac

        case "$cur" in
        --config=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 1
            return 0
            ;;
        --mock-config=*)
            _ddiskit_comp_cfg "${cur#--*=}" "${cur%%=*}=" "$mock_dir" ".cfg"
            return 0
            ;;
        --check-git-src=*)
            _ddiskit_comp_list "${cur#--*=}" "${cur%%=*}=" 0 1 2
            return 0
            ;;
        -[caesmrlg]*)
            w="$cur"
            _ddiskit_strip_opts aesml

            w="${w1}"
            w1="${w:1}"

            case "$w" in
            c*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 1
                return 0
                ;;
            r*)
                _ddiskit_comp_cfg "$w1" "${cur%$w1}" "$mock_dir" ".cfg"
                return 0
                ;;
            g*)
                _ddiskit_comp_list "${w1}" "${cur%$w1}" 0 1 2
                return 0
            esac
        ;;
        esac

        _ddiskit_comp_list "$cur" "" "${build_rpm_opts} ${build_rpm_opts_long}"
        return 0
        ;;
    build_iso)
        for i in $(seq "$cmd_idx" $((cword - 1)) )
        do
            w="${words[$i]}"

            if [ "$skip" = 1 ]
            then
                [ "$before_skip" = "-c" ] && config="$w"

                skip=0
                continue
            fi

            case "$w" in
            --config|--isofile)
                [ "$w" = "--config" ] && before_skip="-c"
                skip=1
                continue
                ;;
            -[ci]*)
                w1="${w:1}"

                if [ "${#w1}" = 1 -a "${w1#[ci]}" != "$w1" ]
                then
                    before_skip="-$w1"
                    skip=1

                    [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
                fi

                continue
                ;;
            esac
        done

        [ "$skip" = 1 ] && case "$prev" in
        -c|--config)
            _ddiskit_comp_file "$cur" "" 1
            return 0
            ;;
        -i|--isofile)
            _ddiskit_comp_file "$cur" "" 0 ".iso"
            return 0
            ;;
        esac

        case "$cur" in
        --config=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 1
            return 0
            ;;
        --isofile=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 0 ".iso"
            return 0
            ;;
        -[ci]*)
            w="${cur:1}"
            w1="${w:1}"

            case "$w" in
            c*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 1
                return 0
                ;;
            i*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 0 ".iso"
                return 0
                ;;
            esac
        ;;
        esac

        # XXX Note that these two calls lead to double-trimming attempt
        #     of options, but in case of command line options which do not
        #     contain any equal signs, this is fine.
        _ddiskit_comp_list "$cur" "" "${build_iso_opts} ${build_iso_opts_long}"
        _ddiskit_comp_file "$cur" "" 0 ".rpm"
        return 0
        ;;
    dump_config)
        for i in $(seq "$cmd_idx" $((cword - 1)) )
        do
            w="${words[$i]}"

            if [ "$skip" = 1 ]
            then
                [ "$before_skip" = "-c" ] && config="$w"

                skip=0
                continue
            fi

            case "$w" in
            --config|--dump-config-name)
                [ "$w" = "--config" ] && before_skip="-c"
                skip=1
                continue
                ;;
            -[co]*)
                w1="${w:1}"

                if [ "${#w1}" = 1 -a "${w1#[co]}" != "$w1" ]
                then
                    before_skip="-$w1"
                    skip=1

                    [ "$i" = "$((cword - 1))" ] && prev="${before_skip}"
                fi

                continue
                ;;
            esac
        done

        [ "$skip" = 1 ] && case "$prev" in
        -c|--config)
            _ddiskit_comp_file "$cur" "" 1
            return 0
            ;;
        -o|--dump-config-name)
            _ddiskit_comp_file "$cur"
            return 0
            ;;
        esac

        case "$cur" in
        --config=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}=" 1
            return 0
            ;;
        --dump-config-name=*)
            _ddiskit_comp_file "${cur#--*=}" "${cur%%=*}="
            return 0
            ;;
        -[co]*)
            w="${cur:1}"
            w1="${w:1}"

            case "$w" in
            c*)
                _ddiskit_comp_file "$w1" "${cur%$w1}" 1
                return 0
                ;;
            o*)
                _ddiskit_comp_file "$w1" "${cur%$w1}"
                return 0
                ;;
            esac
        ;;
        esac

        _ddiskit_comp_list "$cur" "" "${dump_config_opts} ${dump_config_opts_long}"
        return 0
        ;;
    *)
        ;;
    esac
}
complete -o nospace -F _ddiskit ddiskit
