#!/bin/sh

trap auxilium_close INT QUIT TERM

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 "$1" |tr -s '[:upper:]' '[:lower:]'
}

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

auxilium_init() {
    # TODO: Add manage for subcommand
    # Param :
    # App NAME : Mandatory
    # -s: Name of subcommand
    # -m: Help description for Application
    while [ $# -gt 0 ]; do
        _key="$1"
        case $_key in
            -s)
                subname=$2
                shift 2
                ;;
            -m)
                readonly _AXM_APP_DESCR="$2"
                shift 2
                ;;
            *)
                _AXM_APP_NAME=$(_to_lower "$_key")
                readonly _AXM_APP_NAME
                shift 1
                ;;
        esac
    done
    if [ -z "$subname" ]; then
        readonly __AXM_FILE_PREFIX="${_AXM_APP_NAME}"
    else
        readonly __AXM_FILE_PREFIX="${_AXM_APP_NAME}_${subname}"
    fi
    _AXM_ARGS_FILE=$(mktemp -t "${__AXM_FILE_PREFIX}"-auxilium_args.XXXXXX)
    readonly _AXM_ARGS_FILE
    _AXM_ARGS_VALUE=$(mktemp -t "${__AXM_FILE_PREFIX}"-auxilium_value.XXXXXX)
    readonly _AXM_ARGS_VALUE
    _AXM_LIST_ARGS=$(mktemp -t "${__AXM_FILE_PREFIX}"-auxilium_list_args.XXXXXX)
    readonly _AXM_LIST_ARGS
    _AXM_LIST_OPT=$(mktemp -t "${__AXM_FILE_PREFIX}"-auxilium_list_opt.XXXXXX)
    readonly _AXM_LIST_OPT
    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() {
    # TODO: Add manage for subcommand
    # 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
    type='str'
    all=0
    unset name short type default choice callback message
    while [ $# -gt 0 ]; do
        _key="$1"
        case $_key in
            -s)
                short=$2
                shift 2
                ;;
            -t)
                type=$2
                shift 2
                ;;
            -d)
                default=$2
                shift 2
                ;;
            -a)
                all=1
                shift 1
                ;;
            -l)
                choice=$2
                shift 2
                ;;
            -c)
                callback=$2
                shift 2
                ;;
            -m)
                message=$2
                shift 2
                ;;
            *)
                name=$(_to_lower "$_key")
                shift 1
                ;;
        esac
    done
    #NAME^TYPE^SHORT^DEFAULT^ALL^CHOICE^CALLBACK^MESSAGE
    printf "%s^%s^%s^%s^%s^%s^%s^%s\n" \
        "$name" \
        "$type" \
        "$short" \
        "$default" \
        "$all" \
        "$choice" \
        "$callback"  \
        "$message" >> "${_AXM_ARGS_FILE}"
}

auxilium_usage(){
    # TODO: Add manage for subcommand
    tabs 4,20,35,45,60
    # Print usage
    output_args=''
    output_pos=''
    usage_args=''
    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
        def=''
        noopt=''
        name_upper=$(_to_upper "${name}")
        name_lower=$(_to_lower "${name}")
        opt="--${name_lower}"
        if [ -n "${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="\t$(printf "Default: %s" "${default}")"
        fi
        if [ -n "${choice}" ]; then
            def="${def}\t$(printf "Choice: %s" "${choice}")"
        fi
        # shellcheck disable=SC2059
        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%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: "
    # shellcheck disable=SC2059
    printf "${_AXM_APP_NAME}${usage_args}${usage_pos}\n"
    printf "\nOptionals Arguments:"
    # shellcheck disable=SC2059
    printf "${output_args}\n"
    printf "\nPositional Argument:"
    # shellcheck disable=SC2059
    printf "${output_pos}\n\n"
    tabs -8
    exit 0
}

_auxilium_compl(){
    # TODO: Add manage for subcommand
    opts=''
    args=''
    map=''
    while IFS=^ read -r name type short default all choice callback message
    do
        [ "$type" = "positional" ] && continue
        name_lower=$(_to_lower "${name}")
        s=''
        c=''
        if [ "$2" = "bash" ]; then
            if [ -n "${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 [ -n "${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
            # shellcheck disable=SC2059
            m=$(printf "${message}" | sed "s/\//\\\\\//g" |awk -vRS="\n" -vORS=" " '1')
            opts="${opts}    ${s}\'[${m}]\'${c} \\\\\n"
        fi
    done < "${_AXM_ARGS_FILE}"
    template="/usr/share/auxilium/${2}-completion.template"
    if [ -f "/etc/auxilium/${2}-completion.template" ]; then
        template="/etc/auxilium/${2}-completion.template"
    fi
    sed -e "s/{scriptname}/${_AXM_APP_NAME}/g" "$template" \
        -e "s/{opts}/${opts} /g" "$template" \
        -e "s/{args}/${args} /g" "$template" \
        -e "s/{map}/${map} /g" "$template"
    exit 0
}

auxilium_parse(){
    # TODO: Add manage for subcommand
    # Param: Args of the App
    list_args=''
    pos=1
    grep -v "\^positional\^" "${_AXM_ARGS_FILE}" > "$_AXM_LIST_ARGS"
    # Default Values
    while IFS=^ read -r name type short default all choice callback message
    do
        if [ -n "${default}" ]; then
            echo "AUXILIUM_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 [ -n "${short}" ]; then
                opt="^-${short}$\|${opt}"
            fi
            if  expr "$arg" : "$opt" > /dev/null ; then
                axm_find=1
                if [ "${type}" = "opt" ];then
                    echo "readonly AUXILIUM_ARG_${name}='1'" >> "$_AXM_ARGS_VALUE"
                    shift 1
                    if [ -n "${callback}" ]; then
                        ${callback} "${name}" 1
                    fi
                else
                    shift 1
                    if [ -n "${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 "readonly AUXILIUM_ARG_${name}='${list_args}'" >> "$_AXM_ARGS_VALUE"
                    if [ -n "${callback}" ]; then
                        ${callback} "${name}" "${list_args}" 2>/dev/null
                    fi
                fi
                break
            fi
        done < "$_AXM_LIST_ARGS"
        if [ $axm_find -eq 0 ]; then
            grep "\^positional\^" "${_AXM_ARGS_FILE}"| head -${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 $#
            else
                list_args=$1
                shift 1
                
            fi
            echo "readonly AUXILIUM_ARG_${name}='${list_args}'" >> "$_AXM_ARGS_VALUE"
            pos=$((pos + 1))
            if [ -n "${callback}" ]; then
                ${callback} "${name}" "${list_args}" 2>/dev/null
            fi
        fi
    done

    # Set de new variable by source de new temporary file
    # shellcheck disable=SC1090
    . "${_AXM_ARGS_VALUE}"
}

auxilium_close(){
    # Delete temporaries files
    rm -f "${_AXM_ARGS_FILE}" 2>/dev/null
    rm -f "${_AXM_ARGS_VALUE}" 2>/dev/null
    rm -f "${_AXM_LIST_ARGS}" 2>/dev/null
    rm -f "${_AXM_LIST_OPT}" 2>/dev/null
    # TODO: Add rm subcommand file
}
