#!/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é."
}

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' \
    -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
        echo "ulib est en version $pversion"
        if [ -n "$system" ]; then
            setx sversion formatversion 0 0 0
            sversionfile="/etc/.ulibver"
            [ -f "$sversionfile" ] && sversion="$(<"$sversionfile")"
            parseversion "$(<"$versionfile")" s
            echo "/etc/ulib est en version $spversion"
        fi

    elif [ "$action" == set ]; then
        parsepversion "$set_version"
        formatversion >"$versionfile"
        echo "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")"
        echo "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")
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