#!/bin/bash ## Only here for syntax highlighting
# 
# Copyright (c) 2017-2018, SyLabs, Inc. All rights reserved.
# Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
#
# Copyright (c) 2015-2017, Gregory M. Kurtzer. All rights reserved.
# 
# Copyright (c) 2016, The Regents of the University of California, through
# Lawrence Berkeley National Laboratory (subject to receipt of any required
# approvals from the U.S. Dept. of Energy).  All rights reserved.
# 
# This software is licensed under a customized 3-clause BSD license.  Please
# consult LICENSE file distributed with the sources of this project regarding
# your rights to use or distribute this software.
# 
# NOTICE.  This Software was developed under funding from the U.S. Department of
# Energy and the U.S. Government consequently retains certain rights. As such,
# the U.S. Government has been granted for itself and others acting on its
# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the Software
# to reproduce, distribute copies to the public, prepare derivative works, and
# perform publicly and display publicly, and to permit other to do so. 
# 
# 

_singularity_next_nonopt() {
    cmd_idx=$1
    while [ $cmd_idx -lt $COMP_CWORD ]; do
        cmd="${COMP_WORDS[$cmd_idx]}"
        if [[ ${cmd} != -* ]] ; then
            break;
        fi
        cmd_idx=$(( $cmd_idx + 1 ))
    done
    echo $cmd_idx
    return 0
}

_singularity() {
    local cur cmd opts cmd_idx container_idx
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev_opt_idx=$(( $COMP_CWORD - 2))
    prev_opt="${COMP_WORDS[$prev_opt_idx]}"

    # TODO: This can be dynamically generated by the following:
    #   find /opt/singularity/libexec/singularity/cli -maxdepth 1 -mindepth 1 -name '*.exec' -type f -exec basename {} \; | sed -e 's|.exec||' | sort -u
    # but we then need to auto-generate this file with autoconf.
    local -r cmds="help selftest exec run shell test apps bootstrap build check inspect mount pull instance.start instance.list instance.stop image image.create image.import image.export image.expand"

    # Find the first command (skipping any global options)
    cmd_idx=( $(_singularity_next_nonopt 1) )
    cmd="${COMP_WORDS[$cmd_idx]}"

    # In this case, no command is present.
    if [ $cmd_idx -eq $COMP_CWORD ]; then
        if [[ ${cur} == -* ]] ; then
            opts="--debug --help --silent --quiet --version  --verbose --sh-debug"
            COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
            return 0
        else
            COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) )
            return 0
        fi
    fi

    # If another non-option has been specified we will tentatively assume 
    # that it is a container
    container_idx=$(( $cmd_idx + 1 ))
    container_idx=( $(_singularity_next_nonopt $container_idx ) )

    case "${cmd}" in
        help)
            COMPREPLY=( $(compgen -W "$cmds" -- ${cur}) )
            return 0
        ;;

        selftest)
            _filedir
            return 0
        ;;

        run|shell|exec)
            # If we specified a container, treat this as a command (excepting opts with args)
            if [[ ${prev_opt} != -S && ${prev_opt} != --scratch && ${prev_opt} != --pwd && ${prev_opt} != -a && ${prev_opt} != --app && ${prev_opt} != -o && ${prev_opt} != --overlay ]]; then
                if [ $container_idx -lt $COMP_CWORD ]; then
                    if [[ ${cmd} == run || ${cmd} == exec ]]; then
                        _command_offset $(( $COMP_CWORD ))
                        return 0
                    fi
                fi
            fi

            if [[ ${cur} == -B || ${cur} == --bind ]]; then
                #TODO: Not really a path, but this should be a bind spec...
                _filedir
            elif [[ ${cur} == -S || ${cur} == --scratch* || ${cur} == --pwd || ${cur} == -a || ${cur} == --app || ${cur} == -o || ${cur} == --overlay ]]; then
                _filedir
            elif [[ ${cur} == -H || ${cur} == --home ]]; then
                COMPREPLY=( $(compgen -f -- ${cur}) )
            elif [[ ${cur} == -W || ${cur} == --workdir || ${cur} == --wdir ]]; then
                COMPREPLY=( $(compgen -f -- ${cur}) )
            elif [[ ${cur} == -* ]] ; then
                opts="--app --bind --contain --containall --cleanenv --home --ipc --net --no-home --nv --overlay --pid --pwd --scratch --user --workdir --writable --help "
                case "${cmd}" in
                    shell)
                        opts="$opts --shell"
                esac
                COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
            else
                _filedir 
            fi
            return 0
        ;;

        bootstrap)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--notest --section --checks --tag --low --med --high --force --help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;; 

        build)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--sandbox --writable --force --notest --section --checks --tag --low --med --high --help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;;

        apps)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;;

        test)
            if [[ ${cur} == -a || ${cur} == --app ]]; then
                _filedir
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--app --help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;; 

        mount)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--writable --overlay --help" -- ${cur}) )
            else
                _filedir
            fi
            _filedir
            return 0
        ;; 

        create)
            if [[ ${cur} == -s || ${cur} == --size ]]; then
                # Specify a number; no completion. 
                return 0
            elif [[ ${cur} == -* ]] ; then
                 COMPREPLY=( $(compgen -W "--size --force --help" -- ${cur}) )
            elif [ $container_idx -lt $COMP_CWORD ]; then
                return 0
            else
                _filedir
            fi
            return 0
        ;;

        inspect)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--app --labels --deffile --runscript --test --environment --json --helpfile --help" -- ${cur}) )
            elif [ $container_idx -lt $COMP_CWORD ]; then
                return 0
            else
                _filedir
            fi
            return 0
        ;;

        check)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--low --med --high --tag --help" -- ${cur}) )
            elif [ $container_idx -lt $COMP_CWORD ]; then
                return 0
            else
                _filedir
            fi
            return 0
        ;;

        pull)
            if [[ ${cur} == -n || ${cur} == --name ]]; then
                _filedir
            elif [[ ${cur} == -C || ${cur} == --commit ]]; then
                _filedir
            elif [[ ${cur} == -H || ${cur} == --hash ]]; then
                _filedir
            elif [[ ${cur} == -s || ${cur} == --size ]]; then
                return 0
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--name --commit --hash --size --force --help" -- ${cur}) )
            else
                _filedir 
            fi
            return 0
        ;;

        instance.start)
            if [[ ${cur} == -B || ${cur} == --bind ]]; then
                #TODO: Not really a path, but this should be a bind spec...
                _filedir
            elif [[ ${cur} == -S || ${cur} == --scratch* || ${cur} == --pwd ]]; then
                _filedir
            elif [[ ${cur} == -H || ${cur} == --home ]]; then
                COMPREPLY=( $(compgen -f -- ${cur}) )
            elif [[ ${cur} == -W || ${cur} == --workdir || ${cur} == --wdir ]]; then
                COMPREPLY=( $(compgen -f -- ${cur}) )
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--bind --contain --home --net --no-home --nv --overlay --scratch --workdir --writable --help --cleanenv" -- ${cur}) )
            else
                _filedir 
            fi
            return 0
        ;;

        instance.list)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W " --user --json --help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;;

        instance.stop)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--all --user --help" -- ${cur}) )
            elif [ $container_idx -lt $COMP_CWORD ]; then
                return 0
            else
                _filedir
            fi
            return 0
        ;;

        image.create)
            if [[ ${cur} == -s || ${cur} == --size ]]; then
                return 0
            elif [[ ${cur} == -i || ${cur} == --bytes-per-inode ]]; then
                return 0
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--size --force --help --bytes-per-inode" -- ${cur}) )
            else
                _filedir 
            fi
            return 0
        ;;

        image.import)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W " --help" -- ${cur}) )
            else
                _filedir
            fi
            return 0
        ;;

        image.expand)
            if [[ ${cur} == -s || ${cur} == --size ]]; then
                return 0
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--size --help" -- ${cur}) )
            else
                _filedir 
            fi
            return 0
        ;;

        image.export)
            if [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--file --help" -- ${cur}) )
            elif [ $container_idx -lt $COMP_CWORD ]; then
                return 0
            else
                _filedir
            fi
            return 0
        ;;

        instance)
            # In this case, no sub-command is present.
            if [ $container_idx -eq $COMP_CWORD ]; then
                COMPREPLY=( $(compgen -W "start list stop" -- ${cur}) )
                return 0
            # In this case the next non-option is a subcommand not an image
            elif [ $container_idx -lt $COMP_CWORD ]; then
                subcmd="${COMP_WORDS[$container_idx]}"
                container_idx=$(( $container_idx + 1 ))
                container_idx=( $(_singularity_next_nonopt $container_idx ) )
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
                return 0
            fi

            case "${subcmd}" in
                start)
                    if [[ ${cur} == -B || ${cur} == --bind ]]; then
                        #TODO: Not really a path, but this should be a bind spec...
                        _filedir
                    elif [[ ${cur} == -S || ${cur} == --scratch* || ${cur} == --pwd ]]; then
                        _filedir
                    elif [[ ${cur} == -H || ${cur} == --home ]]; then
                        COMPREPLY=( $(compgen -f -- ${cur}) )
                    elif [[ ${cur} == -W || ${cur} == --workdir || ${cur} == --wdir ]]; then
                        COMPREPLY=( $(compgen -f -- ${cur}) )
                    elif [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W "--bind --contain --home --net --no-home --nv --overlay --scratch --workdir --writable --help --cleanenv" -- ${cur}) )
                    else
                        _filedir 
                    fi
                    return 0
                ;;

                list)
                    if [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W " --user --help" -- ${cur}) )
                    else
                        _filedir
                    fi
                    return 0
                ;;

                stop)
                    if [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W "--all --user --help" -- ${cur}) )
                    elif [ $container_idx -lt $COMP_CWORD ]; then
                        return 0
                    else
                        _filedir
                    fi
                    return 0
                ;;

            esac 
        ;;

        image)
            # In this case, no sub-command is present.
            if [ $container_idx -eq $COMP_CWORD ]; then
                COMPREPLY=( $(compgen -W "create import export expand" -- ${cur}) )
                return 0
            # In this case the next non-option is a subcommand not an image
            elif [ $container_idx -lt $COMP_CWORD ]; then
                subcmd="${COMP_WORDS[$container_idx]}"
                container_idx=$(( $container_idx + 1 ))
                container_idx=( $(_singularity_next_nonopt $container_idx ) )
            elif [[ ${cur} == -* ]] ; then
                COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
                return 0
            fi

            case "${subcmd}" in

                create)
                    if [[ ${cur} == -s || ${cur} == --size ]]; then
                        return 0
                    elif [[ ${cur} == -i || ${cur} == --bytes-per-inode ]]; then
                        return 0
                    elif [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W "--size --force --help --bytes-per-inode" -- ${cur}) )
                    else
                        _filedir 
                    fi
                    return 0
                ;;

                import)
                    if [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W " --help" -- ${cur}) )
                    else
                        _filedir
                    fi
                    return 0
                ;;

                export)
                    if [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W "--file --help" -- ${cur}) )
                    elif [ $container_idx -lt $COMP_CWORD ]; then
                        return 0
                    else
                        _filedir
                    fi
                    return 0
                ;;

                expand)
                    if [[ ${cur} == -s || ${cur} == --size ]]; then
                        return 0
                    elif [[ ${cur} == -* ]] ; then
                        COMPREPLY=( $(compgen -W "--size --help" -- ${cur}) )
                    else
                        _filedir 
                    fi
                    return 0
                ;;
            esac 
        ;;
    esac
}

complete -F _singularity singularity

