#!/bin/sh

if [ "$(basename $0)" = "auxilium" ]; then
    echo "You can't use this script directly"
    echo "You can view an example by call /usr/bin/auxilium-test"
    exit
fi

_to_lower(){
    echo $(echo $1 |tr -s '[:upper:]' '[:lower:]')
}

_to_upper(){
    echo $(echo $1 |tr -s '[:lower:]' '[:upper:]')
}

auxilium_init() {
    # Param :
    # App NAME : Mandatory
    # -s: Name of subcommand
    # -m: Help description for Application
    _AXM_SUB_NAME=''
    while [ $# -gt 0 ]; do
        _key="$1"
        case $_key in
            -s)
                _AXM_SUB_NAME=$2
                shift 2
                ;;
            -m)
                _AXM_APP_DESCR=$2
                shift 2
                ;;
            *)
                _AXM_APP_NAME=$(_to_lower $_key)
                shift 1
                ;;
        esac
    done
    if [ -z _AXM_SUB_NAME ]; then
        __AXM_FILE_PREFIX=${_AXM_APP_NAME}
    else
        __AXM_FILE_PREFIX="_${_AXM_APP_NAME}_${_AXM_SUB_NAME}"
    fi
    _AXM_ARGS_FILE=$(mktemp -t ${__AXM_FILE_PREFIX}-auxilium_args.XXXXXX)
    _AXM_ARGS_VALUE=$(mktemp -t ${__AXM_FILE_PREFIX}-auxilium_value.XXXXXX)
    _AXM_LIST_ARGS=$(mktemp -t ${__AXM_FILE_PREFIX}-auxilium_list_args.XXXXXX)
    _AXM_LIST_OPT=$(mktemp -t ${__AXM_FILE_PREFIX}-auxilium_list_opt.XXXXXX)
    auxilium_add help -s h -t opt -m 'This help message' -c auxilium_usage
    auxilium_add 'sh_completion' -t str -l "bash|zsh" -m 'Generate shell completion script' -c _auxilium_compl
}

auxilium_add() {
    # Param:
    # Opt NAME: Mandatory
    # -t type of argument (str by default|opt|positional|subcommand)
    # -s Short option
    # -d Default value
    # -a All remaining arguments, must be last
    # -l List of choices separate by |
    # -c Callback fonction (Arg in parameter)
    # -m Help Message
    unset _AXM_SHORT
    unset _AXM_DEFAULT
    unset _AXM_CALLBACK
    unset _AXM_MESSAGE
    unset _AXM_CHOICE
    _AXM_TYPE='str'
    _AXM_ALL=0
    _AXM_CHOICE=' '
    while [ $# -gt 0 ]; do
        _key="$1"
        case $_key in
            -s)
                _AXM_SHORT=$2
                shift 2
                ;;
            -t)
                _AXM_TYPE=$2
                shift 2
                ;;
            -d)
                _AXM_DEFAULT=$2
                shift 2
                ;;
            -a)
                _AXM_ALL=1
                shift 1
                ;;
            -l)
                _AXM_CHOICE=$2
                shift 2
                ;;
            -c)
                _AXM_CALLBACK=$2
                shift 2
                ;;
            -m)
                _AXM_MESSAGE=$2
                shift 2
                ;;
            *)
                _AXM_NAME=$(_to_lower $_key)
                shift 1
                ;;
        esac
    done
    #NAME^TYPE^SHORT^DEFAULT^ALL^CHOICE^CALLBACK^MESSAGE
    #TYPE is str
    #CHOICE is empty
    printf "%s^%s^%s^%s^%s^%s^%s^%s\n" \
        "$_AXM_NAME" \
        "$_AXM_TYPE" \
        "$_AXM_SHORT" \
        "$_AXM_DEFAULT" \
        "$_AXM_ALL" \
        "$_AXM_CHOICE" \
        "$_AXM_CALLBACK"  \
        "$_AXM_MESSAGE" >> "${_AXM_ARGS_FILE}"
}
 
auxilium_usage(){ 
    tabs 4,16,30,40,60
    # Print usage
    unset _OUTPUT_ARGS
    unset _OUTPUT_POS
    unset _USAGE_ARGS
    unset _USAGE_POS

    printf "Description:\n"
    printf "\t%s\n" "${_AXM_APP_DESCR}"
    while IFS=^ read -r _NAME _TYPE _SHORT _DEFAULT _ALL _CHOICE _CALLBACK _MESSAGE
    do
        unset _DEF
        unset _NOOPT
        unset _OPT
        _NAME_UPPER=$(_to_upper ${_NAME})
        _NAME_LOWER=$(_to_lower ${_NAME})
        _OPT="--${_NAME_LOWER}"
        if [ ! -z "${_SHORT}" ]; then
            _OPT="-${_SHORT}|${_OPT}"
        fi
        if [ "${_TYPE}" != "opt" ];then
            if [ ${_ALL} -eq 1 ]; then
                _NOOPT="${_NAME_UPPER}..."
            else
                _NOOPT="${_NAME_UPPER}"
           fi
        fi
        if [ -n "${_DEFAULT}" ]; then
            _DEF="$(printf "Default: %s" "${_DEFAULT}")"
        elif [ -n "${_CHOICE}" ]; then
           _DEF="$(printf "Choice: %s" "${_CHOICE}")"
        fi
        _MSG=$(printf "${_MESSAGE}" |awk -vRS="\n" -vORS="\n\t\t\t" '1' | sed '$d' )
        if [ "${_TYPE}" = "positional" ];then
            _OUTPUT_POS="${_OUTPUT_POS}\n$(printf '\t%s\n\t\t\t%s\n' "$_NOOPT" "$_MSG")"
            _USAGE_POS="${_USAGE_POS} $(printf '<%s>' "$_NOOPT")"
        else
            _OUTPUT_ARGS="${_OUTPUT_ARGS}\n$(printf '\t%s %s\t%s\n\t\t\t%s' "$_OPT" "$_NOOPT" "$_DEF" "$_MSG")"
            _USAGE_ARGS="${_USAGE_ARGS} $(printf '[%s %s]' "$_OPT" "${_NOOPT}")"
        fi
    done < ${_AXM_ARGS_FILE}
    printf "\nUsage: "
    printf "${_AXM_APP_NAME}${_USAGE_ARGS}${_USAGE_POS}\n"
    printf "\nOptionals Arguments:"
    printf "${_OUTPUT_ARGS}\n"
    printf "\nPositional Argument:"
    printf "${_OUTPUT_POS}\n\n"
    tabs -8
}

_auxilium_compl(){
    local OPTS=''
    local ARGS=''
    local MAP=''
    while IFS=^ read -r _NAME _TYPE _SHORT _DEFAULT _ALL _CHOICE _CALLBACK _MESSAGE
    do
        _NAME_LOWER=$(_to_lower ${_NAME})
        _S=''
        if [ "$2" == "bash" ]; then
            if [ ! -z "${_SHORT}" ]; then
                _S=" -${_SHORT}"
                MAP="${MAP} [-${_SHORT}]=${_NAME_LOWER}"
            fi
            OPTS="${OPTS} [${_NAME_LOWER}]=\'--${_NAME_LOWER}${_S}\'"
            MAP="${MAP} [--${_NAME_LOWER}]=${_NAME_LOWER}"
            if [ "${_TYPE}" == "str" ];then
                _C=$(echo "$_CHOICE"|sed s/'|'/' '/g)
                ARGS="${ARGS} [${_NAME_LOWER}]=\'${_CHOICE}\'"
            fi
        elif [ "$2" == "zsh" ]; then
            if [ ! -z "${_SHORT}" ]; then
                _S="\'(--${_NAME_LOWER} -${_SHORT})\'{--${_NAME_LOWER},-${_SHORT}}"
            else
                _S="--${_NAME_LOWER}"
            fi
            if [ "${_TYPE}" == "str" ];then
                _CH=$(echo "$_CHOICE"|sed s/'|'/' '/g)
                _C=":choice:(${_CH})"
            else
                _C=''
            fi
            _M=$(printf "${_MESSAGE}" |awk -vRS="\n" -vORS=" " '1')
            OPTS="${OPTS}    ${_S}\'[${_M}]\'${_C} \\\\\n"
       fi
    done < ${_AXM_ARGS_FILE}

    if [ - f "/etc/auxilium/${2}-completion.template" ]; then
        _TEMPLATE="/etc/auxilium/${2}-completion.template"
    else
        _TEMPLATE="/usr/share/auxilium/${2}-completion.template"
    fi
    cat $_TEMPLATE | \
        sed -e "s/{scriptname}/${_AXM_APP_NAME}/g" | \
        sed -e "s/{opts}/${OPTS} /g" | \
        sed -e "s/{args}/${ARGS} /g" | \
        sed -e "s/{map}/${MAP} /g"
    exit 0
 }

auxilium_parse(){
    # Param: Args of the App
    _AXM_POS=1
    _POS_MAX_IDX=$(cat $_AXM_ARGS_FILE | grep '\^positional\^' | wc -l)
    cat ${_AXM_ARGS_FILE}| grep -v "\^positional\^" > "$_AXM_LIST_ARGS"
    # Default Values
    while IFS=^ read -r _NAME _TYPE _SHORT _DEFAULT _NUMBER _CHOICE _CALLBACK _MESSAGE
    do
        if [ ! -z "${_DEFAULT}" ]; then
            echo "MAXILIUM_ARG_${_NAME}='${_DEFAULT}'" >> "$_AXM_ARGS_VALUE"
        fi
    done < $_AXM_LIST_ARGS

    while [ $# -gt 0 ] ;
    do
        _ARG="${1}"
        _AXM_FIND=0
        while IFS=^ read -r _NAME _TYPE _SHORT _DEFAULT _ALL _CHOICE _CALLBACK _MESSAGE
        do
            _NAME_LOWER="$(_to_lower ${_NAME})"
            _OPT="^--${_NAME_LOWER}$"
            if [ ! -z "${_SHORT}" ]; then
                _OPT="^-${_SHORT}$\|${_OPT}"
            fi
            if  expr match $_ARG $_OPT > /dev/null ; then
                _AXM_FIND=1
                
                if [ "${_TYPE}" = "opt" ];then
                    echo "MAXILIUM_ARG_${_NAME}='1'" >> "$_AXM_ARGS_VALUE"
                    shift 1
                    if [ ! -z "${_CALLBACK}" ]; then
                        ${_CALLBACK} ${_NAME} 1
                    fi
                else
                    shift 1
                    if [ ! -z "${_CHOICE}" ]; then
                        if (echo "|${_CHOICE}|" | grep -v "|${1}|"); then
                            echo "ERROR: ${1} is not in list of choices ${_CHOICE} for ${_ARG}"
                            exit 1
                        fi
                    fi
                    if [ ${_ALL} -eq 1 ]; then
                        _LIST_ARGS=$@
                        shift $#
                    else
                        _LIST_ARGS=${1}
                        shift 1
                    fi
                    echo "MAXILIUM_ARG_${_NAME}='${_LIST_ARGS}'" >> "$_AXM_ARGS_VALUE"
                    if [ ! -z "${_CALLBACK}" ]; then
                        ${_CALLBACK} ${_NAME} ${_LIST_ARGS} 2>/dev/null
                    fi
                fi
                break
            fi
        done < $_AXM_LIST_ARGS
        if [ $_AXM_FIND -eq 0 ]; then
            cat ${_AXM_ARGS_FILE}| grep "\^positional\^"| head -${_AXM_POS}|tail -1 > "$_AXM_LIST_OPT"
            IFS=^ read -r _NAME _TYPE _SHORT _DEFAULT _ALL _CHOICE _CALLBACK _MESSAGE < "$_AXM_LIST_OPT"
            if [ ${_ALL} -eq 1 ]; then
                _LIST_ARGS=$@
                shift $#
            fi
            echo "MAXILIUM_ARG_${_NAME}='${_LIST_ARGS}'" >> "$_AXM_ARGS_VALUE"
            _AXM_POS=$((_AXM_POS+1))
            if [ ! -z "${_CALLBACK}" ]; then
                ${_CALLBACK} ${_NAME} ${_LIST_ARGS} 2>/dev/null
            fi
        fi
    done

    # Set de new variable by source de new temporary file
    . "${_AXM_ARGS_VALUE}"
}

auxilium_close(){
    # Delete temporaries files
    rm /tmp/${__AXM_FILE_PREFIX}-auxilium*
}
