#compdef ach achd achcop

# Copyright (c) 2015, Rice University.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#     * Redistributions of source code must retain the above
#       copyright notice, this list of conditions and the following
#       disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials
#       provided with the distribution.
#     * Neither the name of the copyright holder nor the names of its
#       contributors may be used to endorse or promote products
#       derived from this software without specific prior written
#       permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.


#########
## ACH ##
#########

(( $+functions[_ach-mk] )) ||
_ach-mk () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '-m[message count]' \
        '-n[nominal message size]' \
        '-o[channel mode]' \
        '-k[kernel channel]' \
        '-u[user channel]' \
        '-1[accept created channel]' \
        '-t[truncate existing channel]' \
        '-a[advertise channel via mDNS]' \
        '-p[port number to advertise]' \
        '*:: :->channel' && return

    return ret
}

function ach_list_channels {
    if [ -d /dev/ach ]; then
        ls /dev/ach/ | sed -e 's!^ach-!!'
    fi
    if [ -d /run/shm ]; then
        find /run/shm -name 'achshm-*' | sed -e 's!^/run/shm/achshm-!!'
    elif [ -d /dev/shm ]; then
        find /dev/shm -name 'achshm-*' | sed -e 's!^/dev/shm/achshm-!!'
    fi
}

function ach_browse_channels {
    avahi-browse _ach._tcp -cp | cut -d ';' -f 4 | sort | uniq
}


(( $+functions[_ach-rm] )) ||
_ach-rm () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}

(( $+functions[_ach-chmod] )) ||
_ach-chmod () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        ':: :->mode' \
        ':: :->channel' \
        && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}

(( $+functions[_ach-file] )) ||
_ach-file () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}


(( $+functions[_ach-search] )) ||
_ach-search () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_browse_channels` && ret=0
            ;;
    esac

    return ret
}

(( $+functions[_ach-adv] )) ||
_ach-adv () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '-p[port number to use]:port' \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}

(( $+functions[_ach-hide] )) ||
_ach-hide () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}

(( $+functions[_ach-dump] )) ||
_ach-dump () {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '*:: :->channel' && return

    case "$state" in
        (channel)
            compadd `ach_list_channels` && ret=0
            ;;
    esac

    return ret
}

function _ach_commands {
    local -a commands
    commands=(
        mk:'create a channel'
        rm:'remove a channel'
        chmod:'change channel permissions'
        search:'resolve channel host'
        file:'display backing file for channel'
        dump:'display information about channel'
        adv:'advertise channel via mDNS '
        hide:'stop mDNS advertisement for channel'
    )

    integer ret=1
    _describe -t commands 'command' commands && ret=0
    return ret
}

function __ach {
    local curcontext="$curcontext" state line
    declare -A opt_args

    _arguments -C \
        '-V[display version information]' \
        '-?[display help]' \
        '-v[increase verbosity]' \
        '(-): :->command' \
        '(-)*:: :->option-or-argument' && return 0

    integer ret=1
    case $state in
        (command)
            _ach_commands && ret=0
            ;;
        (option-or-argument)
            curcontext=${curcontext%:*:*}:ach-$words[1]:

            if (( $+functions[_ach-$words[1]] )); then
                _call_function ret _ach-$words[1]
            else
                _message 'unknown sub-command'
            fi
            ;;
    esac

    return ret
}

############
## ACHCOP ##
############

function __achcop {
    local curcontext="$curcontext" state line
    declare -A opt_args

    _arguments -C \
        '-V[display version information]' \
        '-?[display help]' \
        '-v[increase verbosity]' \
        '-P[parent PID file]' \
        '-p[child PID file]' \
        '-o[stdout redirect file]' \
        '-e[stderr redirect file]' \
        '-d[detach and run in background]' \
        '-r[restart failed children]' \
        '-f[syslog facility]' \
        '-i[syslog identifier]' \
        && return 0

    integer ret=1

    return ret
}

##########
## ACHD ##
##########

function achd_client {
    local curcontext=$curcontext state line ret=1
    declare -A opt_args

    _arguments -C \
        '-p [remote port to use]' \
        '-t [message transport (tcp|udp)]' \
        '-z [remote channel name (default: local name)]' \
        '-u [transmit period in microseconds]' \
        '-l [transmit latest messages]' \
        '-r [reconnect if disconnected]' \
        '*:: :->channel' && return

    return ret
}

(( $+functions[_achd-push] )) ||
_achd-push () {
    achd_client
}

(( $+functions[_achd-pull] )) ||
_achd-pull () {
    achd_client
}

function _achd_commands {
    local -a commands
    commands=(
        push:'send frames to remote host'
        pull:'receive frames from remote host'
        serve:'run server on stdin/stdout'
    )

    integer ret=1
    _describe -t commands 'command' commands && ret=0
    return ret
}

function __achd {
    local curcontext="$curcontext" state line
    declare -A opt_args

    _arguments -C \
        '-V[display version information]' \
        '-?[display help]' \
        '-v[increase verbosity]' \
        '-q[decrease verbosity]' \
        '(-): :->command' \
        '(-)*:: :->option-or-argument' && return 0

    integer ret=1
    case $state in
        (command)
            _achd_commands && ret=0
            ;;
        (option-or-argument)
            curcontext=${curcontext%:*:*}:achd-$words[1]:

            if (( $+functions[_achd-$words[1]] )); then
                _call_function ret _achd-$words[1]
            else
                _message 'unknown sub-command'
            fi
            ;;
    esac

    return ret
}

##############
## DISPATCH ##
##############

# Need the double underscore to prevent zsh from automagically calling
# the wrong completion function.  We dispatch here:
case "$service" in
    ach)
        __ach "$@"
        ;;
    achcop)
        __achcop "$@"
        ;;
    achd)
        __achd "$@"
        ;;
esac

# Local Variables:
# mode: shell-script
# End:
