#!/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: Gestion des librairies ulib et pyulib

USAGE
    $scriptname [options] --destdir DESTDIR [options]
    $scriptname [options] --version [options]
    $scriptname [options] --shell [options]

SYNCHRONISER ULIB/PYULIB
    -S, --sync
        Synchroniser ulib, pyulib et les scripts de support
    -d, --destdir DESTDIR
        Synchroniser ulib et/ou pyulib dans le répertoire destdir.
        Les options -u et -p permettent de choisir ce qui est synchronisé
    -u, --ulib
        Copier/mettre à jour ulib (par défaut)
    -p, --pyulib
        Copier/mettre à jour pyulib
    -s, --support
        Copier/mettre à jour les scripts de support

GERER LA VERSION DE ULIB
    -v, --version
        Gérer la version de ulib
    -l, --show
        Afficher la version de la librairie (par défaut)
    -s, --system
        Afficher aussi la version de la librairie système
    -c, --check MIN_VERSION
        Vérifier que la version de la librairie est au minimum MIN_VERSION, et
        afficher un message d'information. Utiliser l'option -q si l'on veut
        juste tester la version et ne pas afficher le message d'information.
    -V, --set-version VERSION
        Forcer la version de ulib
    -u, --update
        Incrémenter la version de ulib. Les options -x, -z, -p permettent de
        choisir le numéro qui est incrémenté.
    -x, --major
        Augmenter le numéro de version majeure
    -z, --minor
        Augmenter le numéro de version mineure. C'est l'option par défaut
    -p, --patchlevel
        Augementer le numéro de patch

LANCER UN SHELL (par défaut)
    -s, --shell
        Lancer un shell dans lequel les modules de ulib spécifiés sont chargés.
        De plus, PATH est modifié pour que $scriptdir soit ajouté en premier.
        Les arguments restants sont passés inchangés au shell.
    -r, --require module
        Spécifier un module à charger avec urequire. Plusieurs modules peuvent
        être spécifiés en les séparant par ':'
        Par défaut, seul le module DEFAULTS est chargé.
    --force-reload
        Forcer le (re)chargement des modules avec urequire. Cette option est
        utile pour le développement. En effet, dans le shell, la commande
        'urequire module' (re)charge toujours le module, même s'il avait déjà
        été chargé."
}

function formatversion() {
    local major="${1:-${major:-0}}" minor="${2:-${minor:-0}}" patch="${3:-${patch:-0}}"
    while [ ${#major} -lt 3 ]; do major="0$major"; done
    while [ ${#minor} -lt 3 ]; do minor="0$minor"; done
    while [ ${#patch} -lt 3 ]; do patch="0$patch"; done
    echo "$major$minor$patch"
}

function parsepversion() {
    local v M m p
    if [[ "$1" == *.* ]]; then
        local v="$1"; shift
        local M=0 m=0 p=0
        if [[ "$v" == *.* ]]; then
            p="${v##*.}"; v="${v%.*}"
            if [[ "$v" == *.* ]]; then
                m="${v##*.}"; v="${v%.*}"
                if [[ "$v" == *.* ]]; then
                    M="${v##*.}"; v="${v%.*}"
                else
                    M="$v"
                fi
            else
                m="$v"
            fi
        else
            p="$v"
        fi
        parseversion "$(formatversion "$M" "$m" "$p")" "$@"
    else
        parseversion "$@"
    fi
}

function parseversion() {
    if [ -n "$2" ]; then
        local version="${1:-${version:-000000000}}"
        local major minor patch pversion
    else
        version="${1:-${version:-000000000}}"
    fi
    while [ ${#version} -lt 9 ]; do version="0$version"; done
    major="${version:0:3}"; while [ ${#major} -gt 1 -a "${major#0}" != "$major" ]; do major="${major#0}"; done
    minor="${version:3:3}"; while [ ${#minor} -gt 1 -a "${minor#0}" != "$minor" ]; do minor="${minor#0}"; done
    patch="${version:6:3}"; while [ ${#patch} -gt 1 -a "${patch#0}" != "$patch" ]; do patch="${patch#0}"; done
    pversion="$major.$minor.$patch"
    [ -n "$2" ] && eval "${2}version=\$version; ${2}major=\$major; ${2}minor=\$minor; ${2}patch=\$patch; ${2}pversion=\$pversion"
}

# mode de fonctionnement
case "$scriptname" in
ulibsync) mode=sync;;
ulibversion) mode=version;;
ulibshell) mode=shell;;
*) mode=auto;;
esac

# mode sync
destdir=
syncwhat=auto
synculib=
syncpyulib=
syncsupport=
# mode version
action=show
system=
min_version=
set_version=
inc_version=minor
# mode shell
modules=()
# options courtes partagées
u_opt=; p_opt=; s_opt=
parse_opts + "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -S,--sync mode=sync \
    -d:,--destdir: '$mode=sync; set@ destdir' \
    --ulib '$mode=sync; syncwhat=; synculib=1' \
    --pyulib '$mode=sync; syncwhat=; syncpyulib=1' \
    --support '$mode=sync; syncwhat=; syncsupport=1' \
    -v,--version mode=version \
    -l,--show '$mode=version; action=show' \
    --system '$mode=version; action=show; system=1' \
    -c:,--check: '$mode=version; action=check; set@ min_version' \
    -V:,--set-version: '$mode=version; action=set; set@ set_version' \
    --update '$mode=version; action=inc' \
    -x,--major '$mode=version; action=inc; inc_version=major' \
    -z,--minor '$mode=version; action=inc; inc_version=minor' \
    --patchlevel '$mode=version; action=inc; inc_version=patch' \
    --shell mode=shell \
    -r:,--require: '$mode=shell; add@ modules' \
    --force-reload '$mode=shell; __ULIB_FORCE_RELOAD=1' \
    -u u_opt=1 \
    -p p_opt=1 \
    -s s_opt=1 \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

case "$mode" in
auto)
    mode=
    if [ -n "$u_opt" ]; then
        mode=version; action=inc
    fi
    if [ -n "$p_opt" -a -n "$u_opt" ]; then
        # support de -up
        mode=version; action=inc; inc_version=patch
    elif [ -n "$p_opt" ]; then
        die "getopt: invalid option 'p'"
    fi
    if [ -n "$s_opt" ]; then
        mode=shell
    fi
    ;;
esac
[ -n "$mode" ] || mode=shell

case "$mode" in
sync)
    [ -n "$u_opt" ] && { syncwhat=; synculib=1; }
    [ -n "$p_opt" ] && { syncwhat=; syncpyulib=1; }
    [ -n "$s_opt" ] && { syncwhat=; syncsupport=1; }
    [ "$syncwhat" == auto ] && {
        synculib=1
        #syncpyulib=
        #syncsupport=
    }

    [ -n "$destdir" ] || destdir="$1"
    [ -z "$destdir" -a -n "$synculib" -a -d lib/ulib ] && destdir=lib
    [ -z "$destdir" -a -n "$syncpyulib" -a -d lib/pyulib ] && destdir=lib
    [ -n "$destdir" ] || destdir=.

    ask_yesno "Voulez-vous copier ${synculib:+
- la librairie ulib}${syncpyulib:+
- la librairie pyulib}${syncsupport:+
- scripts de support}
dans $(ppath "$destdir")?" O || die

    urequire install

    if [ -n "$synculib" ]; then
        __ulib_install_show_args ulib "$destdir" 1
        ulibsync "$destdir"
    fi
    if [ -n "$syncpyulib" ]; then
        urequire pyulib/pyulib
        __ulib_install_show_args pyulib "$destdir" 1
        pyulibsync "$destdir"
    fi
    if [ -n "$syncsupport" ]; then
        adestdir="$(abspath "$destdir")"
        for i in .nutools-bootstrap; do
            if [ "${adestdir%/lib}" != "$adestdir" ]; then
                # cas particulier: synchro vers un répertoire lib/
                # dans ce cas, copier le fichier .nutools-bootstrap dans le
                # répertoire parent.
                copy_update "$scriptdir/$i" "$(dirname -- "$destdir")"
            else
                copy_update "$scriptdir/$i" "$destdir"
            fi
        done
        # calculer le nom du répertoire de destination, pour nommer les fichiers
        # local-uinst
        destpfix="${adestdir%/lib}"
        destpfix="${destpfix##*/}"
        destpfix="${destpfix:-local}"
        for i in lib/ulib/support/local-uinst lib/ulib/support/local-uinst.sh; do
            destname="$destpfix-${i#lib/ulib/support/local-}"
            copy_update "$scriptdir/$i" "$destdir/$destname"
        done
    fi
    exit 0
    ;;

version)
    [ -n "$u_opt" ] && { action=inc; }
    [ -n "$p_opt" ] && { action=inc; inc_version=patch; }
    [ -n "$s_opt" ] && { action=show; system=1; }

    setx version formatversion 0 0 0
    versionfile="$scriptdir/lib/ulib/.ulibver"
    [ -f "$versionfile" ] || echo "$version" >"$versionfile"
    [ -f "$versionfile" ] && version="$(<"$versionfile")"
    parseversion "$(<"$versionfile")"

    if [ "$action" == set -o "$action" == inc ]; then
        [ -f "$scriptdir/.nutools-devel" ] ||
        die "Cette installation de ulib est déjà déployé en version $pversion: impossible de la mettre à jour."
    fi

    if [ "$action" == show ]; then
        if [ -n "$system" ]; then
            setx sversion formatversion 0 0 0
            sversionfile="/etc/.ulibver"
            [ -f "$sversionfile" ] && sversion="$(<"$sversionfile")"
            parseversion "$(<"$versionfile")" s
        fi
        if isatty; then
            eecho "ulib est en version $pversion"
            [ -n "$system" ] && eecho "/etc/ulib est en version $spversion"
        else
            echo "$pversion"
            [ -n "$system" ] && echo "$spversion"
        fi

    elif [ "$action" == set ]; then
        parsepversion "$set_version"
        formatversion >"$versionfile"
        eecho "ulib est maintenant en version $pversion"

    elif [ "$action" == inc ]; then
        case "$inc_version" in
        major) major=$(($major + 1)); minor=0; patch=0;;
        minor) minor=$(($minor + 1)); patch=0;;
        patch) patch=$(($patch + 1));;
        esac
        formatversion >"$versionfile"
        parseversion "$(<"$versionfile")"
        eecho "ulib est maintenant en version $pversion"

    elif [ "$action" == check ]; then
        r=1
        parsepversion "$min_version" m
        [ "$version" -ge "$mversion" ] && r=0
        if [ $r -eq 0 ]; then
            eecho "ulib est en version $pversion >= $mpversion ${COULEUR_VERTE}[OK]${COULEUR_NORMALE}"
        else
            eecho "ulib est en version $pversion < $mpversion ${COULEUR_ROUGE}[KO]${COULEUR_NORMALE}"
        fi
        exit $r

    else
        die "BUG: action inconnue $action"
    fi
    ;;
shell)
    [ -n "$u_opt" ] && die "getopt: invalid option 'u'"
    [ -n "$p_opt" ] && die "getopt: invalid option 'p'"
    [ -n "$s_opt" ] && { mode=shell; } # FYI, ici $mode vaut déjà shell

    ac_set_tmpfile bashrc
    echo "\
if ! grep -q '/etc/bash.bashrc' /etc/profile; then
  [ -f /etc/bash.bashrc ] && source /etc/bash.bashrc
fi
if ! grep -q '~/.bashrc' ~/.bash_profile; then
  [ -f ~/.bashrc ] && source ~/.bashrc
fi
[ -f /etc/profile ] && source /etc/profile
[ -f ~/.bash_profile ] && source ~/.bash_profile
if ! grep -q '$scriptdir/bashrc' ~/.bashrc; then
  if [ -f '$scriptdir/bashrc' ]; then
    if ! grep -q @@dest@@ '$scriptdir/bashrc'; then
      # ne lire que si le répertoire est déployé
      source '$scriptdir/bashrc'
    fi
  fi
  function uprovide() { :; }
  source '$scriptdir/lib/ulib/uenv'
  __uenv_source_dirs '$scriptdir/lib/bashrc.d'
  __uenv_cleanup
fi
if ! grep -q '$scriptdir/profile' ~/.bash_profile; then
  if [ -f '$scriptdir/profile' ]; then
    if grep -q @@dest@@ '$scriptdir/profile'; then
      # répertoire non déployé
      # la ligne suivante est copiée du fichier profile
      [ -z '$USER' -a -n '$LOGNAME' ] && export USER='$LOGNAME'
    else
      # ne lire que si le répertoire est déployé
      source '$scriptdir/profile'
    fi
  fi
  function uprovide() { :; }
  source '$scriptdir/lib/ulib/uenv'
  __uenv_source_dirs '$scriptdir/lib/profile.d'
  __uenv_cleanup
fi

# Modifier le PATH. Ajouter aussi le chemin vers les uapps python
PATH=$(quoted_args "$scriptdir:$scriptdir/lib/pyulib/src/uapps:$PATH")

if [ -n '$DEFAULT_PS1' ]; then
  DEFAULT_PS1=$(quoted_args "[ulibshell] $DEFAULT_PS1")
else
  if [ -z '$PS1' ]; then
    PS1='\\u@\\h \\w \\$ '
  fi
  PS1=\"[ulibshell] \$PS1\"
fi
$(quoted_args source "$scriptdir/lib/ulib/ulib")
__ULIB_FORCE_RELOAD=$(quoted_args "$__ULIB_FORCE_RELOAD")
urequire DEFAULTS" >"$bashrc"

    array_fix_paths modules
    if [ -n "${modules[*]}" ]; then
        etitle "Chargement des modules"
        for module in "${modules[@]}"; do
            estep "$module"
            quoted_args urequire "$module" >>"$bashrc"
        done
        eend
    fi

    estep "Lancement du sous-shell"
    "$SHELL" --rcfile "$bashrc" -i -- "$@"
    # note: ne pas faire exec "$SHELL", parce que sinon le fichier temporaire bashrc
    # n'est pas supprimé

    ac_clean "$bashrc"
    ;;
esac