##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Fonction de support pour gérer le déploiement d'artifacts
##@cooked nocomments

################################################################################
# API publique

function deploy_query() {
    deploy_query_once "$@" && return 0
    if [ -n "$QUERYVARS" ]; then
        deploy_query_recursive "$@" && return 0
    fi
    return 1
}

function deploy_query_recursive() {
    local DFILE
    for DFILE in "${QUERYVARS[@]}"; do
        (
            deploy_loadconf --no-auto-update
            deploy_query_once "$@" && exit 0
            if [ -n "$QUERYVARS" ]; then
                deploy_query_recursive "$@" && exit 0
            fi
            exit 1
        ) && return 0
    done
    return 1
}

function deploy_query_once() {
    # Afficher le résultat d'une requête
    local alv sov sdv slv sof sdf slf
    eval "set -- $(getopt -ov:odl -lallow-vars:,object-vars,dest-vars,link-vars,of:,object-func:,df:,dest-func:,lf:,link-func: -- "$@")"
    while [ -n "$1" ]; do
        case "$1" in
        -v|--allow-vars)
            array_split alv "$2" ,
            shift; shift
            ;;
        -o|--object-vars) sov=1; shift;;
        -d|--dest-vars) sdv=1; shift;;
        -l|--link-vars) slv=1; shift;;
        --of|--object-func) sof="$2"; shift; shift;;
        --df|--dest-func) sdf="$2"; shift; shift;;
        --lf|--link-func) slf="$2"; shift; shift;;
        --) shift; break;;
        *) break;;
        esac
    done

    local qtype="$1" otype="$2" ltype="$3" profile="$4" format="${5:-shell}" term="$6"
    local -a vs; local object type link

    case "$qtype" in
    DEST|SOURCE)
        if [ -n "$otype" ]; then
            deploy_is_type "$otype" || {
                [ "$format" == shell ] && qvals false "$otype: invalid type"
                return 2
            }
        fi
        ;;
    *)
        if [ -n "$qtype" ]; then
            deploy_is_type "$qtype" || {
                [ "$format" == shell ] && qvals false "$qtype: invalid type"
                return 3
            }
        fi
        ;;
    esac
    if [ -n "$ltype" ]; then
        deploy_is_link "$ltype" || {
            [ "$format" == shell ] && qvals false "$ltype: invalid link type"
            return 4
        }
    fi
    [ -n "$term" ] || {
        [ "$format" == shell ] && qvals false "search term required"
        return 5
    }

    case "$qtype" in
    DEST)
        edebug "=== search type DEST"
        edebug "term=$term, otype=$otype"
        deploy_search_artifact object type "$term" "$otype" host || {
            [ "$format" == shell ] && qvals false "artifact not found"
            return 1
        }
        edebug "object=$object, type=$type"
        deploy_search_link link "$type" "$ltype" || {
            [ "$format" == shell ] && qvals false "link not found"
            return 1
        }
        
        deploy_show_values object object "$format" shell alv
        deploy_show_values type otype "$format" shell alv
        deploy_show_values link ltype "$format" shell alv
        if [ -n "$sov" ]; then
            deploy_copy_object_values vs "$object" "$type"
            deploy_show_values vs "$type" "$format" shell alv
            deploy_show_attrs "$object" "$type" "$format" alv vars "$sof"
        fi
        if [ -n "$sdv" ]; then
            local -a pons pgns ons gns ans ovs os; local an av o
            deploy_prepare_copy_link_attrs pons pgns ons gns "$object" "$link" "$profile"
            deploy_copy_link_attr_values hvs host "$object" "$link" "$profile" pons pgns ons gns
            for hv in "${hvs[@]}"; do
                deploy_copy_object_values hs "$hv" host
                deploy_show_values hs host "$format" shell alv
                deploy_show_attrs "$hn" host "$format" alv vars "$sdf"
            done
        fi
        deploy_show_links "$object" "$link" "$profile" "$format" "" alv vars "$slf"
        [ "$format" == shell ] && echo true
        return 0
        ;;
    SOURCE)
        # XXX implémenter
        [ "$format" == shell ] && echo true
        return 0
        ;;
    *)
        if deploy_search_artifact object type "$term" "$qtype"; then
            deploy_copy_object_values vs "$object" "$type"
            deploy_show_values object object "$format" shell alv
            deploy_show_values type otype "$format" shell alv
            deploy_show_values vs "$type" "$format" ""  alv
            deploy_show_attrs "$object" "$type" "$format" alv
            [ "$format" == shell ] && echo true
            return 0
        fi
        [ "$format" == shell ] && qvals false "artifact not found"
        return 1
        ;;
    esac
}

function deploy_setconf() {
    local confname="$1" confdir="$2"
    if [ -n "$confdir" ]; then
        confdir="$(abspath "$confdir")"
        if [[ "$confname" == */* ]] || [[ "$confname" == *.* ]]; then
            local d="$(abspath "$(dirname -- "$confname")")"
            if [ "$d" != "$confdir" ]; then
                CONFNAME="$confname"
                SFILE="$CONFNAME"
                DFILE="${CONFNAME%.conf}.vars"
                return
            fi
            confname="$(basename -- "$confname" .conf)"
        fi
        CONFNAME="${confname:-deploy}"
        IFILE="$confdir/init.conf"
        SFILE="$confdir/$CONFNAME.conf"
    else
        CONFNAME="${confname:-deploy}"
        IFILE=
        SFILE=
    fi
    if is_root; then
        DFILE="/var/local/deploy/$CONFNAME.vars"
    else
        DFILE="$HOME/etc/deploy/$CONFNAME.vars"
    fi
}

function deploy_loadconf() {
    # charger la configuration. deploy_setconf() DOIT être appelé avant
    if [ "$1" != --no-auto-update ]; then (
        # mettre à jour le cas échéant le fichier des variables
        DEPLOY_SRCDIR=; set_defaults deploy
        [ -n "$DEPLOY_SRCDIR" ] || DEPLOY_SRCDIR=~/wop/deploy
        [ -x "$DEPLOY_SRCDIR/query" ] && "$DEPLOY_SRCDIR/query" --nop -c "$CONFNAME"
    ); fi
    [ -f "$DFILE" ] && source "$DFILE" || return 1
}

function deploy_search_artifact() {
    local do="$1" dt="$2" term="$3" type="$4" nottype="$5"
    local -a ts os vs; local t o v object

    deploy_copy_types ts
    for t in "${ts[@]}"; do
        [ -n "$type" -a "$t" != "$type" ] && continue
        [ -n "$nottype" -a "$t" == "$nottype" ] && continue

        object=
        if deploy_is_object "$term" "$t"; then
            # on a déjà le bon identifiant
            object="$term"
        else
            # chercher un identifiant correspondant à la valeur
            deploy_copy_objects os "$t"
            for o in "${os[@]}"; do
                deploy_copy_object_values vs "$o" "$t"
                if array_contains vs "$term"; then
                    object="$o"
                    break
                fi
                if [[ "$term" != *.* ]]; then
                    for v in "${vs[@]}"; do
                        if [ "${v%%.*}" == "$term" ]; then
                            object="$o"
                            break
                        fi
                    done
                fi
            done
            if [ -z "$object" ]; then
                # essayer sans tenir compte de la casse
                for o in "${os[@]}"; do
                    if [ "${o,,}" == "${term,,}" ]; then
                        object="$o"
                        break
                    fi
                    deploy_copy_object_values vs "$o" "$t"
                    for v in "${vs[@]}"; do
                        if [ "${v,,}" == "${term,,}" ]; then
                            object="$o"
                            break
                        fi
                    done
                    if [[ "$term" != *.* ]]; then
                        for v in "${vs[@]}"; do
                            v="${v%%.*}"
                            if [ "${v,,}" == "${term,,}" ]; then
                                object="$o"
                                break
                            fi
                        done
                    fi
                done
            fi
        fi
        if [ -n "$object" ]; then
            upvars "$do" "$object" "$dt" "$t"
            return 0
        fi
    done
    return 1
}

function deploy_search_link() {
    local dl="$1" type="$2" link="$3"
    local -a ls ts; local l
    deploy_copy_links ls
    for l in "${ls[@]}"; do
        [ -n "$link" -a "$l" != "$link" ] && continue

        deploy_copy_link_types ts "$l"
        if array_contains ts "$type"; then
            upvar "$dl" "$l"
            return 0
        fi
    done
    return 1
}

function deploy_show_values() {
    if [ -n "$5" ]; then
        if ! array_isempty "$5"; then
            array_contains "$5" "$2" || return
        fi
    fi
    local -a __sv_vs; array_copy __sv_vs "$1"
    local -a vs; array_copy vs __sv_vs
    local t="$2" f="${3:-shell}" ff="$4"
    [ -n "$ff" -a "$f" != "$ff" ] && return

    case "$f" in
    shell) deploy_dump_values "$t" vs;;
    line) array_to_lines vs;;
    *) array_join vs "$f";;
    esac
}

function deploy_show_attrs() {
    if [ -n "$4" ]; then
        local -a __dsa_alv; array_copy __dsa_alv "$4"
        local -a alv; array_copy alv __dsa_alv
    fi
    local o="$1" t="$2" f="${3:-shell}" ff=shell
    [ -n "$ff" -a "$f" != "$ff" ] && return

    local -a ons gns ans vs; local an
    deploy_prepare_copy_attrs ons gns "$o" "$t"
    deploy_copy_attr_names ans "$o" "$t" ons gns
    [ -n "$5" ] && echo_seta "${t}_vars" "${ans[@]}"
    for an in "${ans[@]}"; do
        if [ -n "$4" ]; then
            if ! array_isempty "$4"; then
                array_contains alv "$an" || continue
            fi
        fi
        deploy_copy_attr_values vs "$an" "$o" "$t" ons
        deploy_dump_values "$an" vs
    done
    [ -n "$6" ] && echo "$6"
}

function deploy_show_links() {
    if [ -n "$6" ]; then
        local -a __dsl_alv; array_copy __dsl_alv "$6"
        local -a alv; array_copy alv __dsl_alv
    fi
    local o="$1" l="$2" profile="$3" f="${4:-shell}" ff="$5"
    local -a ps pons pgns ons gns ans ovs os; local p an av o
    [ -n "$ff" -a "$f" != "$ff" ] && return

    deploy_copy_profiles ps 1
    for p in "${ps[@]}"; do
        [ -n "$profile" -a "$p" != "$profile" ] && continue
        deploy_show_values p profile "$format" shell alv

        deploy_prepare_copy_link_attrs pons pgns ons gns "$o" "$l" "$p"
        deploy_copy_link_attr_names ans "$o" "$l" "$p" pons pgns ons gns
        [ -n "$7" -a "$f" == shell ] && echo_seta "${l}_vars" "${ans[@]}"
        for an in "${ans[@]}"; do
            deploy_copy_link_attr_values avs "$an" "$o" "$l" "$p" pons pgns ons gns
            if [ "$an" == host ]; then
                # toujours montrer host
                #deploy_show_values avs "$an" "$f" "$ff"
                ovs=()
                for av in "${avs[@]}"; do
                    deploy_copy_object_values os "$av" host
                    array_extendu ovs os
                done
                deploy_show_values ovs host "$f" "$ff" alv
            else
                deploy_show_values avs "$an" "$f" shell alv
            fi
        done
        [ -n "$8" -a "$f" == shell ] && echo "$8"
    done
}

################################################################################
# Fonctions bas niveau

function deploy_is_profile() {
    # tester si $1 est un profil valide
    [ -z "$1" ] && return 0 # pas de profil == profil valide
    array_contains LISTOF_PROFILES "$1"
}
function deploy_copy_profiles() {
    # copier la liste des profils valides dans le tableau $1
    # si LISTOF_PROFILES est vide et que $2!="", alors mettre une chaine vide
    # dans le tableau $1
    array_upvar "$1" "${LISTOF_PROFILES[@]}"
    if array_isempty "$1" && [ -n "$2" ]; then
        array_add "$1" ""
    fi
}
function deploy_is_type() {
    # tester si $1 est un type valide
    array_contains LISTOF_TYPES "$1"
}
function deploy_copy_types() {
    # copier la liste des types valides dans le tableau $1
    array_upvar "$1" "${LISTOF_TYPES[@]}"
}
function deploy_is_object() {
    # tester si $1 est un objet valide de type $2
    local o="$1" t="${2:-host}"
    array_contains "LISTOF_${t}s" "$o"
}
function deploy_copy_objects() {
    # copier la liste des objets valides de type $2 dans le tableau $1
    local d="$1" t="${2:-host}"
    local -a os
    array_copy os "LISTOF_${t}s"
    array_upvar "$d" "${os[@]}"
}
function deploy_copy_object_values() {
    local d="$1" o="$2" t="${3:-host}"
    local -a vs
    array_copy vs "${o}_${t}"
    array_upvar "$d" "${vs[@]}"
}
function deploy_prepare_copy_attrs() {
    local dons="$1" dgns="$2" o="$3" t="${4:-host}"
    local -a ons gns
    array_copy ons "LISTOF_${o}_${t}_vars"
    array_copy gns "LISTOF_${t}_vars"
    upvars \
        -a${#ons[*]} "$dons" "${ons[@]}" \
        -a${#gns[*]} "$dgns" "${gns[@]}"
}
function deploy_copy_attr_names() {
    local d="$1" o="$2" t="${3:-host}" __pca_ons="$4" __pca_gns="$5"
    local -a ns
    if [ -n "$__pca_ons" -a -n "$__pca_gns" ]; then
        # variables ons et gns déjà préparées par deploy_prepare_copy_attrs()
        array_copy ns "$__pca_ons"
        array_extendu ns "$__pca_gns"
    else
        local -a ons gns
        array_copy ons "LISTOF_${o}_${t}_vars"
        array_copy gns "LISTOF_${t}_vars"
        array_copy ns ons
        array_extendu ns gns
    fi
    array_upvar "$d" "${ns[@]}"
}
function deploy_copy_attr_values() {
    local d="$1" n="$2" o="$3" t="${4:-host}" __pca_ons="$5"
    local -a vs ns
    local n
    if [ -n "$__pca_ons" ]; then
        # variables ons déjà préparée par deploy_prepare_copy_attrs()
        if array_contains "$__pca_ons" "$n"; then
            array_copy vs "${o}_${t}_${n}"
        else
            array_copy vs "${t}_${n}"
        fi
    else
        local -a ons gns
        array_copy ons "LISTOF_${o}_${t}_vars"
        array_copy gns "LISTOF_${t}_vars"
        if array_contains ons "$n"; then
            array_copy vs "${o}_${t}_${n}"
        else
            array_copy vs "${t}_${n}"
        fi
    fi
    array_upvar "$d" "${vs[@]}"
}

function deploy_is_link() {
    # tester si $1 est un type de lien valide
    array_contains LISTOF_LINKS "$1"
}
function deploy_copy_links() {
    array_upvar "$1" "${LISTOF_LINKS[@]}"
}
function deploy_copy_link_types() {
    local d="$1" l="${2:-deploy}"
    local -a ts
    array_copy ts "LISTOF_${l}_LINKTO"
    array_upvar "$d" "${ts[@]}"
}
function deploy_prepare_copy_link_attrs() {
    local dpons="$1" dpgns="$2" dons="$3" dgns="$4" o="$5" l="${6:-deploy}" p="$7"
    local -a pons pgns ons gns
    if [ -n "$p" ]; then
        array_copy pons "LISTOF_${p}__${o}_${l}_vars"
        array_copy pgns "LISTOF_${p}__${l}_vars"
    fi
    array_copy ons "LISTOF_${o}_${l}_vars"
    array_copy gns "LISTOF_${l}_vars"
    upvars \
        -a${#pons[*]} "$dpons" "${pons[@]}" \
        -a${#pgns[*]} "$dpgns" "${pgns[@]}" \
        -a${#ons[*]} "$dons" "${ons[@]}" \
        -a${#gns[*]} "$dgns" "${gns[@]}"
}
function deploy_copy_link_attr_names() {
    local d="$1" o="$2" l="${3:-deploy}" p="$4"
    local __pca_pons="$5" __pca_pgns="$6" __pca_ons="$7" __pca_gns="$8"
    local -a ns
    if [ -n "$__pca_pons" -a -n "$__pca_pgns" -a -n "$__pca_ons" -a -n "$__pca_gns" ]; then
        # variables pons, pgns, ons et gns déjà préparées par la fonction
        # deploy_prepare_copy_link_attrs()
        array_copy ns "$__pca_pons"
        array_extendu ns "$__pca_pgns"
        array_extendu ns "$__pca_ons"
        array_extendu ns "$__pca_gns"
    else
        local -a pons pgns ons gns
        if [ -n "$p" ]; then
            array_copy pons "LISTOF_${p}__${o}_${l}_vars"
            array_copy pgns "LISTOF_${p}__${l}_vars"
        fi
        array_copy ons "LISTOF_${o}_${l}_vars"
        array_copy gns "LISTOF_${l}_vars"
        array_copy ns pons
        array_extendu ns pgns
        array_extendu ns ons
        array_extendu ns gns
    fi
    array_upvar "$d" "${ns[@]}"
}
function deploy_copy_link_attr_values() {
    local d="$1" n="$2" o="$3" l="${4:-deploy}" p="$5"
    local __pca_pons="$6" __pca_pgns="$7" __pca_ons="$8" __pca_gns="$9"
    local -a vs ns
    local n
    if [ -n "$__pca_pons" -a -n "$__pca_pgns" -a -n "$__pca_ons" -a -n "$__pca_gns" ]; then
        # variables pons et ons déjà préparées par la fonction
        # deploy_prepare_copy_link_attrs()
        if array_contains "$__pca_pons" "$n"; then
            array_copy vs "${p}__${o}_${l}_${n}"
        elif array_contains "$__pca_pgns" "$n"; then
            array_copy vs "${p}__${l}_${n}"
        elif array_contains "$__pca_ons" "$n"; then
            array_copy vs "${o}_${l}_${n}"
        else
            array_copy vs "${l}_${n}"
        fi
    else
        local -a pons pgns ons gns
        if [ -n "$p" ]; then
            array_copy pons "LISTOF_${p}__${o}_${l}_vars"
            array_copy pgns "LISTOF_${p}__${l}_vars"
        fi
        array_copy ons "LISTOF_${o}_${l}_vars"
        array_copy gns "LISTOF_${l}_vars"
        if array_contains pons "$n"; then
            array_copy vs "${p}__${o}_${l}_${n}"
        elif array_contains pgns "$n"; then
            array_copy vs "${p}__${l}_${n}"
        elif array_contains ons "$n"; then
            array_copy vs "${o}_${l}_${n}"
        else
            array_copy vs "${l}_${n}"
        fi
    fi
    array_upvar "$d" "${vs[@]}"
}

function deploy_dump_values() {
    local -a __dv_vs; array_copy __dv_vs "$2"; local -a vs; array_copy vs __dv_vs
    local n="$1" indent="$3"
    case ${#vs[*]} in
    0) echo "$indent$n=";;
    1) echo "$indent$n=$(qvalr "$vs")";;
    *) echo "$indent$n=($(qvals "${vs[@]}"))";;
    esac
}