shopt -s progcomp
_juju () {
    local cur cmds cmdIdx cmd cmdOpts fixedWords i globalOpts
    local curOpt optEnums
    local IFS=$' \n'

    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    cmds='add-relation add-unit bootstrap debug-hooks debug-log deploy destroy-environment destroy-service expose open-tunnel remove-relation remove-unit resolved scp set scp ssh status terminate-machine unexpose upgrade-charm get'
    globalOpts=( -h --verbose -v --log-file)

    # do ordinary expansion if we are anywhere after a -- argument
    for ((i = 1; i < COMP_CWORD; ++i)); do
        [[ ${COMP_WORDS[i]} == "--" ]] && return 0
    done

    # find the command; it's the first word not starting in -
    cmd=
    for ((cmdIdx = 1; cmdIdx < ${#COMP_WORDS[@]}; ++cmdIdx)); do
        if [[ ${COMP_WORDS[cmdIdx]} != -* ]]; then
            cmd=${COMP_WORDS[cmdIdx]}
            break
        fi
    done

    # complete command name if we are not already past the command
    if [[ $COMP_CWORD -le cmdIdx ]]; then
        COMPREPLY=( $( compgen -W "$cmds ${globalOpts[*]}" -- "$cur" ) )
        return 0
    fi

    # find the option for which we want to complete a value
    curOpt=
    if [[ $cur != -* ]] && [[ $COMP_CWORD -gt 1 ]]; then
        curOpt=${COMP_WORDS[COMP_CWORD - 1]}
        if [[ "$curOpt" == = ]]; then
            curOpt=${COMP_WORDS[COMP_CWORD - 2]}
        elif [[ "$cur" == : ]]; then
            cur=
            curOpt="$curOpt:"
        elif [[ "$curOpt" == : ]]; then
            curOpt=${COMP_WORDS[COMP_CWORD - 2]}:
        fi
    fi

    cmdOpts=( )
    optEnums=( )
    fixedWords=( )
    case "$cmd" in
        add-relation|debug-hooks|destroy-environment|destory-service|expose-service|unexpose-service|open-tunnel|remove-relation|remove-unit|scp|set|scp|ssh|terminate-machine)
            cmdOpts=( --environment --help)
            ;;
        get)
            cmdOpts=( --environment --help --schema)
            ;;
        bootstrap)
            cmdOpts=( --environment --help)
            ;;
        add-unit)
            cmdOpts=( --environment --num-units --help)
	    ;;
        deploy)
            cmdOpts=( --environment --num-units --repository --config --help)
            ;;
        debug-log)
            cmdOpts=( --environment --exclude --include --replay --level --limit --output --help)
            case "$curOpt" in
                -l) optEnums=( DEBUG INFO ERROR WARNING CRITICAL ) ;;
            esac
            ;;
        resolved)
            cmdOpts=( --retry --environment --help)
            ;;
        status)
            cmdOpts=( --output --format --environment --help)
            case "$curOpt" in
                --format) optEnums=( json yaml png svg dot ) ;;
            esac
            ;;
        upgrade-charm)
            cmdOpts=( --dry-run --environment --repository --help)
            ;;
        *)
            cmdOpts=(--help)
            ;;
    esac

    IFS=$'\n'
    if [[ "$cur" == = ]] && [[ ${#optEnums[@]} -gt 0 ]]; then
        # complete directly after "--option=", list all enum values
        COMPREPLY=( "${optEnums[@]}" )
        return 0
    else
        fixedWords=( "${cmdOpts[@]}"
                     "${globalOpts[@]}"
                     "${optEnums[@]}"
                     "${fixedWords[@]}" )
    fi

    if [[ ${#fixedWords[@]} -gt 0 ]]; then
        COMPREPLY=( $( compgen -W "${fixedWords[*]}" -- "$cur" ) )
    fi

    return 0
}

complete -F _juju -o default juju
