#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS

function display_help() {
    uecho "$scriptname: lancer une machine virtuelle VirtualBox

USAGE
    $scriptname [options] vmName

OPTIONS
    -n, --nop
        Ne rien faire excepté s'assurer que les modules VirtualBox sont chargés
    -l, --list
        Lister les machines virtuelles
    -s, --start
        Démarrer la machine virtuelle. C'est l'action par défaut.
        Si le nom de la machine virtuelle n'est pas spécifiée, un menu est
        affiché
    -x, --gui
    -b, --headless
    --separate
        Ces options ne sont valides qu'avec -s et permettent de spécifier le
        type de démarrage: 'gui' permet d'afficher une fenêtre complète dans
        laquelle l'accélération graphique est supportée, headless démarre la
        machine en tâche de fond, et separate affiche une fenêtre qui attaque la
        machine démarrée en tâche de fond. --separate est l'option par défaut.
    -k, -t, --stop
        Arrêter la machine virtuelle. Les options -p, -H, -R, -S et -r
        permettent de spécifier le type d'arrêt de la machine virtuelle
    -p, --sleep
        Mettre en veille la machine virtuelle (par ACPI)
    -H, --poweroff
        Arrêter sauvagement la machine virtuelle
    -R, --reset
        Redémarrer sauvagement la machine virtuelle
    -S, --savestate
        Enregistrer l'état de la machine virtuelle
    -r, --rrestart
        Arrêter la machine, restaurer l'état du dernier snapshot puis la
        relancer.
    -g, --gui
        Afficher le gestionnaire de machines virtuelle"
}

function build_arrays() {
    # Construire les listes avms, rvms, svms
    # rvms: les vms qui tournent
    # avms: toutes les vms
    # svms: les vms qui sont arrêtées
    rvms=()
    eval "$(VBoxManage -q list runningvms | awk '{gsub(/[^"]*$/, ""); print}' | csort | sed 's/^/array_add rvms /g')" #"'bug colorisation
    avms=()
    eval "$(VBoxManage -q list vms | awk '{gsub(/[^"]*$/, ""); print}' | csort | sed 's/^/array_add avms /g')" #"'bug colorisation
    svms=()
    for avm in "${avms[@]}"; do
        array_contains rvms "$avm" || array_add svms "$avm"
    done
}

function is_numeric() {
    [ -n "$1" -a -z "${1//[0-9]/}" ]
}

function select_vm() {
    # Afficher un menu pour sélectionner la machine virtuelle
    simple_menu "${2:-vm}" "${1:-avms}" \
        -t "Machines virtuelles" \
        -m "${3:-Choisissez la VM}"
}

function start_virtualbox() {
    # Lancer le gestionnaire de machines virtuelles
    # Les mesures prises le sont pour compatibilité avec Fedora, si la commande
    # est lancée depuis le menu. En effet, toutes les processus fils sont tués
    # s'ils ne sont pas détachés avant la fin de la commande du menu. Le délai
    # est donc pour laisser le temps à VirtualBox de s'initialiser.
    nohup >/dev/null 2>&1 VirtualBox &
    sleep 3
}

action=start
type=separate
stopaction=acpipowerbutton
restore=
parse_opts + "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -n,--nop action=nop \
    -l,--list action=list \
    -s,--start action=start \
    -x,--gui type=gui \
    -b,--background,--headless type=headless \
    --separate type=separate \
    -k,-t,--stop '$action=stop; stopaction=acpipowerbutton' \
    -p,--sleep '$action=stop; stopaction=acpisleepbutton' \
    -H,--poweroff '$action=stop; stopaction=poweroff' \
    -R,--reset '$action=stop; stopaction=reset' \
    -S,--savestate '$action=stop; stopaction=savestate' \
    -r,--rrestart '$action=stop; restore=1' \
    -g,--gui action=gui \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

"$scriptdir/EnsureVM" virtualbox || die
[ "$action" == "nop" ] && exit 0

build_arrays

vm="$1"; shift
if [ -n "$vm" ]; then
    if ! array_contains avms "$vm" && is_numeric "$vm"; then
        vm=$(($vm - 1))
        vm="${avms[$vm]}"
        enote "Sélection de la VM $vm"
    fi
fi

if [ "$action" == list ]; then
    for avm in "${avms[@]}"; do
        if array_contains rvms "$avm"; then
            avm="$(get_color @ g)$avm [running]$(get_color z)"
        fi
        echo "$avm$state"
    done

elif [ "$action" == start ]; then
    if [ -z "$vm" -a -n "${svms[*]}" ]; then
        [ -n "${rvms[*]}" ] &&
        einfo "Les machines virtuelles suivantes sont déjà démarées:
$(array_join rvms "
" "" "    ")" #"
        select_vm svms vm "Choisissez la VM à démarrer"
    fi

    if [ -n "$vm" ]; then
        estep "Démarrage de $vm de type $type"
        VBoxManage -q startvm --type "$type" "$vm" "$@"
    else
        ewarn "Aucune VM à démarrer n'a été trouvée"
    fi

elif [ "$action" == stop ]; then
    if [ -z "$vm" -a "${rvms[*]}" ]; then
        select_vm rvms vm "Choisissez la VM à arrêter avec la méthode $stopaction"
    fi
    [ -n "$vm" ] || die

    estep "Arrêt de $vm avec la méthode $stopaction"
    VBoxManage -q controlvm "$vm" "$stopaction" || die
    if [ -n "$restore" ]; then
        ebegin "Attente de l'arrêt"
        while true; do
            build_arrays
            array_contains svms "$vm" && break
            edot 0
            sleep 1
        done
        eend
        estep "Restauration du snapshot"
        VBoxManage -q snapshot "$vm" restorecurrent || die
        estep "Démarrage"
        VBoxManage -q startvm --type "$type" "$vm"
    fi

elif [ "$action" == gui ]; then
    start_virtualbox
fi
