# $Id: _ncbi_clparser_completion.sh 366096 2012-06-11 21:17:40Z kazimird $
#
# Implementation of a bash completion function for the command
# line interfaces based on the ncbi::CCommandLineParser class.
#
# And since the format of parameter descriptions generated by
# ncbi::CCommandLineParser is almost identical to the format used
# by the Subversion command line client (svn), this completion
# function can be used for svn just as well.
#
# To enable this completion function for 'grid_cli' and 'svn',
# add the following lines to ~/.bash_profile:
#
# compfile=/am/ncbiapdata/bin/_ncbi_clparser_completion.sh
# if test -f "$compfile"; then
#     source "$compfile"
#
#     compfile="/am/ncbiapdata/bin/_ncbi_clparser_opt_compl.sh"
#     test -f "$compfile" && source "$compfile"
#
#     complete -o default -F _ncbi_clparser_completion grid_cli
#     complete -o default -F _ncbi_clparser_completion svn
# fi
#
# Author: Dmitry Kazimirov <kazimird@ncbi.nlm.nih.gov>

_ncbi_clparser_completion()
{
    COMPREPLY=()
    local program="${COMP_WORDS[0]}"
    local program_alias=$(alias "$program" 2> /dev/null | perl -wne "
            s/'\\\\''/'/g; s/.*='(.*)'\$/\$1/; print")
    local implicit_opts=''
    if test -n "$program_alias"; then
        set $program_alias
        program="$1"
        shift
        implicit_opts="$*"
    fi
    local cword="${COMP_WORDS[COMP_CWORD]}"
    local line="${COMP_LINE::COMP_POINT}"
    [[ $line != *$cword ]] && cword="${line##* }"
    local pword="${COMP_WORDS[COMP_CWORD-1]}"
    [[ $pword = '=' && $COMP_CWORD -gt 1 ]] && \
        pword="${COMP_WORDS[COMP_CWORD-2]}"
    local word cmd opts
    for word in "${COMP_WORDS[@]:1}"; do
        if [[ $word != -* ]]; then
            [[ ! $cmd ]] && cmd="$word"
        elif [[ $word != $cword ]]; then
            if [[ $word == --* ]]; then
                opts="$opts ${word%%=*}"
            else
                opts="$opts ${word:0:2}"
            fi
        fi
    done
    if [[ $cword == $cmd || $cmd == 'help' ]]; then
        COMPREPLY=($(compgen -W "$("$program" $implicit_opts \
            help 2> /dev/null | perl -ne '
            if (!$parse) {$parse = m/commands:/o; next}
            if (@cmd = m/^\s{2,4}([a-z]\S+)(?: \(([^)]+)\))?/o) {
                print map {" $_"} grep {length() > 2}
                    $cmd[0], split(m/[ ,]+/, $cmd[1] || "")
            }')" -- "$cword"))
    elif [[ -z $cword || $cword == -* && $cword != --*=* ]]; then
        [[ -z $cmd ]] && cmd="${COMP_LINE:COMP_POINT}" && cmd="${cmd%% *}"
        local compl="$("$program" $implicit_opts \
            help "$cmd" 2> /dev/null | perl -e '
            %spec_opts = map {$_ => 1} split(" ", $ARGV[0]);
            $pword = $ARGV[1];
            while (<STDIN>) {last if m/options:/o}
            while (<STDIN>) {
                if (@opt = m/^\s{2,4}(-\S+) (?:\[([^\]]+)\] )?(ARG)?/io) {
                    %opt = map {$_ => 1} $opt[0], split(m/[ ,]+/, $opt[1] || "");
                    if ($opt{$pword} && $opt[2]) {print "ARG"; exit}
                    next if grep {$spec_opts{$_}} keys %opt;
                    push @compl, grep {length() > 4} @opt
                }
            }
            print " $_" for @compl' -- "$opts" "$pword")"
        if [[ $compl != 'ARG' ]]; then
            COMPREPLY=($(compgen -W "$compl" -- "$cword"))
        else
            COMPREPLY=($(compgen -W " $(_ncbi_clparser_opt_compl \
                "$program" "$pword" "$cword" 2> /dev/null)"))
        fi
    elif [[ $pword == --* ]]; then
        "$program" help "$cmd" 2> /dev/null |
            grep -- "$pword" 2> /dev/null |
            grep -qiw ARG &&
                COMPREPLY=($(compgen -W " $(_ncbi_clparser_opt_compl \
                    "$program" "$pword" "$cword" 2> /dev/null)"))
    fi
}
