##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Affichage en couleur, et support de niveaux de "verbosité" et d'interaction
##@cooked nocomments
##@require base
uprovide pretty
urequire base

################################################################################
# Gestion des couleurs

function __get_color() {
    [ -z "$*" ] && set RESET
    echo_ $'\e['
    local sep
    while [ -n "$1" ]; do
        [ -n "$sep" ] && echo_ ";"
        case "$1" in
        z|RESET) echo_ "0";;
        o|BLACK) echo_ "30";;
        r|RED) echo_ "31";;
        g|GREEN) echo_ "32";;
        y|YELLOW) echo_ "33";;
        b|BLUE) echo_ "34";;
        m|MAGENTA) echo_ "35";;
        c|CYAN) echo_ "36";;
        w|WHITE) echo_ "37";;
        DEFAULT) echo_ "39";;
        O|BLACK_BG) echo_ "40";;
        R|RED_BG) echo_ "41";;
        G|GREEN_BG) echo_ "42";;
        Y|YELLOW_BG) echo_ "43";;
        B|BLUE_BG) echo_ "44";;
        M|MAGENTA_BG) echo_ "45";;
        C|CYAN_BG) echo_ "46";;
        W|WHITE_BG) echo_ "47";;
        DEFAULT_BG) echo_ "49";;
        @|BOLD) echo_ "1";;
        -|FAINT) echo_ "2";;
        _|UNDERLINED) echo_ "4";;
        ~|REVERSE) echo_ "7";;
        n|NORMAL) echo_ "22";;
        esac
        sep=1
        shift
    done
    echo_ "m"
}
function get_color() {
    [ -n "$NO_COLORS" ] && return
    __get_color "$@"
}
function __set_no_colors() {
    if [ -z "$1" ]; then
        if [ -n "$UTOOLS_NO_COLORS" ]; then NO_COLORS=1
        elif out_isatty && err_isatty; then NO_COLORS=
        else NO_COLORS=1
        fi
    else
        is_yes "$1" && NO_COLORS=1 || NO_COLORS=
    fi
    COULEUR_ROUGE="$(get_color RED BOLD)"
    COULEUR_VERTE="$(get_color GREEN BOLD)"
    COULEUR_JAUNE="$(get_color YELLOW BOLD)"
    COULEUR_BLEUE="$(get_color BLUE BOLD)"
    COULEUR_BLANCHE="$(get_color WHITE BOLD)"
    COULEUR_NORMALE="$(get_color RESET)"
}
__set_no_colors

function __eerror() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}* error:${COULEUR_NORMALE} $(__indent "$1")"; }
function __ewarn() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}* warning:${COULEUR_NORMALE} $(__indent "$1")"; }
function __enote() { tooenc "$(__edate)${__tlevel}${COULEUR_VERTE}* note:${COULEUR_NORMALE} $(__indent "$1")"; }
function __ebanner() {
    local maxi="${COLUMNS:-80}"
    local -a lines
    local psfix line

    psfix="$(__edate)${__tlevel}"
    while [ ${#psfix} -lt $maxi ]; do psfix="$psfix="; done

    tooenc "$COULEUR_ROUGE$psfix"
    maxi=$(($maxi - 1))
    array_from_xlines lines "$1"
    for line in "" "${lines[@]}" ""; do
        line="$(__edate)${__tlevel}= $line"
        if [ ${#line} -le $maxi ]; then
            while [ ${#line} -lt $maxi ]; do line="$line "; done
            line="$line="
        fi
        tooenc "$line"
    done
    tooenc "$psfix$COULEUR_NORMALE"
}
function __eimportant() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}* important:${COULEUR_NORMALE} $(__indent "$1")"; }
function __eattention() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}* attention:${COULEUR_NORMALE} $(__indent "$1")"; }
function __einfo() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}* info:${COULEUR_NORMALE} $(__indent "$1")"; }
function __edebug() { tooenc "$(__edate)${__tlevel}${COULEUR_BLANCHE}* debug:${COULEUR_NORMALE} $(__indent "$1")"; }
function __estep() { tooenc "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepe() { tooenc "$(__edate)${__tlevel}${COULEUR_ROUGE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepw() { tooenc "$(__edate)${__tlevel}${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepn() { tooenc "$(__edate)${__tlevel}${COULEUR_VERTE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepi() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estep_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepe_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_ROUGE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepw_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepn_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_VERTE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __estepi_() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLEUE}*${COULEUR_NORMALE} $(__indent "$1")"; }
function __etitle() { tooenc "$(__edate)${__tlevel}${COULEUR_BLEUE}+++ $(get_color _)$(__indent "$1")${COULEUR_NORMALE}"; }
function __ebegin() { tooenc_ "$(__edate)${__tlevel}${COULEUR_BLANCHE}*${COULEUR_NORMALE} $(__indent "$1"): "; }
function __edoto() { echo_ "."; }
function __edotw() { echo_ "${COULEUR_JAUNE}w${COULEUR_NORMALE}"; }
function __edotx() { echo_ "${COULEUR_ROUGE}x${COULEUR_NORMALE}"; }
function __edotp() { echo_ "${COULEUR_JAUNE}+${COULEUR_NORMALE}"; }
function __edotd() { tooenc "($1)"; }
function __eendo() { echo "${COULEUR_VERTE}[ok]${COULEUR_NORMALE}"; }
function __eendx() { echo "${COULEUR_ROUGE}[error]${COULEUR_NORMALE}"; }

# 5=afficher les messages de debug; 4=afficher les message verbeux;
# 3=afficher les message informatifs; 2=afficher les warnings et les notes;
# 1=afficher les erreurs; 0=ne rien afficher
export __verbosity
[ -z "$__verbosity" ] && __verbosity=3
function set_verbosity() {
    [ -z "$__verbosity" ] && __verbosity=3
    case "$1" in
    -Q|--very-quiet) __verbosity=0;;
    -q|--quiet) [ "$__verbosity" -gt 0 ] && let __verbosity=$__verbosity-1;;
    -v|--verbose) [ "$__verbosity" -lt 5 ] && let __verbosity=$__verbosity+1;;
    -c|--default) __verbosity=3;;
    -D|--debug) __verbosity=5; DEBUG=1;;
    *) return 1;;
    esac
    return 0
}
# 3=interaction maximale; 2=interaction par défaut
# 1= interaction minimale; 0=pas d'interaction
export __interaction
[ -z "$__interaction" ] && __interaction=2
function set_interaction() {
    [ -z "$__interaction" ] && __interaction=2
    case "$1" in
    -b|--batch) __interaction=0;;
    -y|--automatic) [ "$__interaction" -gt 0 ] && let __interaction=$__interaction-1;;
    -i|--interactive) [ "$__interaction" -lt 3 ] && let __interaction=$__interaction+1;;
    -c|--default) __interaction=2;;
    *) return 1;;
    esac
    return 0
}
# Variable à inclure pour lancer automatiquement set_verbosity et
# set_interaction en fonction des arguments de la ligne de commande. A utiliser
# de cette manière:
#   parse_opts ... "${PRETTYOPTS[@]}" @ args -- ...
PRETTYOPTS=(
    -L:,--log-to: '$elogto $value_'
    -Q,--very-quiet,-q,--quiet,-v,--verbose,-D,--debug '$set_verbosity $option_'
    -b,--batch,-y,--automatic,-i,--interactive '$set_interaction $option_'
)

function show_error() { [ "$__verbosity" -ge 1 ]; }
function show_warn() { [ "$__verbosity" -ge 2 ]; }
function show_info() { [ "$__verbosity" -ge 3 ]; }
function show_verbose() { [ "$__verbosity" -ge 4 ]; }
function show_debug() { [ -n "$DEBUG" -o "$__verbosity" -ge 5 ]; }
# Vérifier le niveau de verbosité actuel par rapport à l'argument. $1 peut valoir:
# -Q  retourner true si on peut afficher les messages d'erreur
# -q  retourner true si on peut afficher les messages d'avertissement
# -c  retourner true si on peut afficher les message normaux
# -v  retourner true si on peut afficher les messages verbeux
# -D  retourner true si on peut afficher les messages de debug
function check_verbosity() {
    case "$1" in
    -Q|--very-quiet) [ "$__verbosity" -ge 1 ];;
    -q|--quiet) [ "$__verbosity" -ge 2 ];;
    -c|--default) [ "$__verbosity" -ge 3 ];;
    -v|--verbose) [ "$__verbosity" -ge 4 ];;
    -D|--debug) [ -n "$DEBUG" -o "$__verbosity" -ge 5 ];;
    *) return 0;;
    esac
}
# Retourner l'option correspondant au niveau de verbosité actuel
function get_verbosity_option() {
    case "$__verbosity" in
    0) echo --very-quiet;;
    1) echo --quiet --quiet;;
    2) echo --quiet;;
    4) echo --verbose;;
    5) echo --debug;;
    esac
}
# Vérifier le niveau d'interaction autorisé par rapport à l'argument. Par
# exemple, 'check_interaction -y' signifie "Il ne faut interagir avec
# l'utilisateur qu'à partir du niveau d'interaction -y. Suis-je dans les
# condition voulues pour autoriser l'interaction?"
# $1 peut valoir:
# -b  retourner true
# -y  retourner true si on est au moins en interaction minimale
# -c  retourner true si on est au moins en interaction normale
# -i  retourner true si on est au moins en interaction maximale
function check_interaction() {
     case "$1" in
    -b|--batch) return 0;;
    -y|--automatic) [ -n "$__interaction" -a "$__interaction" -ge 1 ];;
    -c|--default) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
    -i|--interactive) [ -n "$__interaction" -a "$__interaction" -ge 3 ];;
    *) return 0;;
    esac
}
# Vérifier le niveau d'interaction dans lequel on se trouve actuellement. $1
# peut valoir:
# -b  retourner true si l'une des options -b ou -yy a été spécifiée
# -Y  retourner true si l'une des options -b, -yy, ou -y a été spécifiée
# -y  retourner true si l'option -y a été spécifiée
# -c  retourner true si aucune option n'a été spécifiée
# -i  retourner true si l'option -i a été spécifiée
# -C  retourner true si aucune option ou l'option -i ont été spécifiés
function is_interaction() {
     case "$1" in
    -b|--batch) [ -n "$__interaction" -a "$__interaction" -eq 0 ];;
    -Y) [ -n "$__interaction" -a "$__interaction" -le 1 ];;
    -y|--automatic) [ -n "$__interaction" -a "$__interaction" -eq 1 ];;
    -c|--default) [ -n "$__interaction" -a "$__interaction" -eq 2 ];;
    -i|--interactive) [ -n "$__interaction" -a "$__interaction" -eq 3 ];;
    -C) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
    *) return 1;;
    esac
}
# Retourner l'option correspondant au niveau d'interaction actuel
function get_interaction_option() {
    case "$__interaction" in
    0) echo --batch;;
    1) echo --automatic;;
    3) echo --interactive;;
    esac
}

##XXX les fonctions ci-dessous restent à migrer
##function edot() {
##    # Une étape d'une opération commencée par ebegin, matérialisée par un "."
##    # Si l'argument est un fichier, utiliser -f pour que "$HOME" et "$(pwd)/"
##    # soient remplacés respectivement par "~" et "" (afin que les chemins soient
##    # plus courts)
##    # Si l'argument est un commentaire, utiliser -m pour le spécifier. -w
##    # indique que l'argument est un warning: un x jaune est affiché, avec le
##    # message associé si on est en mode debug.
##    # Sinon, l'argument est un status. 0 affiche un ".", sinon on affiche un "x"
##    local status=$?
##    local warn= color=
##
##    if [ -n "$utools_edot_first_" ]; then
##        # au premier dot, afficher un espace d'abord
##        echo_ " "
##        utools_edot_first_=
##    fi
##
##    eval `check_verbosity --action "$1" 2`
##    if is_debug; then
##        local msg paths path
##        if [ "$1" = "-f" ]; then
##            # chemins
##            shift
##            for path in "$@"; do
##                paths="${paths:+$paths,}$(ppath "$path")"
##            done
##            msg="$paths"
##        elif [ "$1" = "-m" -o "$1" = "-w" ]; then
##            # message
##            [ "$1" = "-w" ] && warn=1 # message de warning
##            shift
##            msg="$(tooenc "$*")"
##        else
##            # status
##            [ -n "$1" ] && status="$1"
##        fi
##
##        [ "$utools_ESTATUS_" -eq 0 -a "$status" -ne 0 ] && utools_ESTATUS_="$status"
##        if [ "$status" -eq 0 -a -z "$warn" ]; then
##            echo_ "${msg:+
##  }.${msg:+($msg)}"
##        else
##            color="$COULEUR_ROUGE"
##            [ -n "$warn" ] && color="$COULEUR_JAUNE"
##            echo_ "${msg:+
##  }${color}x${COULEUR_NORMALE}${msg:+($msg)}"
##        fi
##    else
##        if [ "$1" = "-f" -o "$1" = "-m" -o "$1" = "-w" ]; then
##            [ "$1" = "-w" ] && warn=1 # message de warning
##            shift
##        else
##            [ -n "$1" ] && status="$1"
##        fi
##
##        [ "$utools_ESTATUS_" -eq 0 -a "$status" -ne 0 ] && utools_ESTATUS_="$status"
##        if [ "$status" -eq 0 -a -z "$warn" ]; then
##            echo_ "."
##        else
##            color="$COULEUR_ROUGE"
##            [ -n "$warn" ] && color="$COULEUR_JAUNE"
##            echo_ "${color}x${COULEUR_NORMALE}"
##        fi
##    fi
##}