#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

if [ $# -eq 1 -a "$1" == --nutools-completion ]; then
    echo '
function __pdev_completion() {
    local cur
    _get_comp_words_by_ref cur
    COMPREPLY=($(compgen -W "$(__pdev_branches)" "$cur"))
}
complete -F __pdev_completion pdev
'
    exit 0
fi

source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS ptools

function display_help() {
    uecho "$scriptname: basculer sur une branche de développement

USAGE
    $scriptname [FEATURE [SOURCE]]
    $scriptname -m|-l|-d [FEATURE]

- Vérifier l'existence de la branche develop. La créer si nécessaire en la
  basant sur [origin/]master.
- Vérifier s'il n'y a pas de modifications locales. Sinon, proposer de faire un
  commit ou un stash.
- Si FEATURE est spécifié, et si on n'est pas déjà sur cette branche, basculer
  vers cette nouvelle branche. S'il s'agit d'une nouvelle branche, la baser sur
  la branche SOURCE, qui vaut par défaut develop
- Si FEATURE n'est pas spécifié, basculer sur develop s'il s'agit de la seule
  solution, sinon afficher un menu pour choisir la branche de destination.

OPTIONS
    -C, --projdir PROJDIR
        Spécifier le répertoire de base du projet qui est dans git. Par défaut,
        on travaille dans le répertoire courant et on laisse git trouver le
        répertoire de base du projet. Avec cette option, le répertoire courant
        est modifié avant de lancer les commandes git.
    -O, --origin ORIGIN
        Spécifier le nom de l'origine. Par défaut, utiliser 'origin'
    -o, --offline
        En cas de création d'une branche, ne pas pousser vers l'origine; ne pas
        tenter le cas échéant de traquer la branche dans l'origine; ne pas
        supprimer une branche dans l'origine. Cette option est automatiquement
        activée si la variable UTOOLS_VCS_OFFLINE est définie.
    --online
        Annuler l'effet de la variable UTOOLS_VCS_OFFLINE: forcer le mode online

    -m, --merge
        Si la branche actuelle est une feature branch, la merger dans develop
        puis la supprimer. Puis basculer sur la branche develop.
    --merge-log
        Ajouter un résumé des modifications sur la feature branch dans le
        message du merge
    -k, --keep
        Avec l'option -m, ne pas supprimer une feature branch après l'avoir
        fusionnée dans develop.
    --delete
        Supprimer une feature branch, à condition qu'elle aie déjà été
        entièrement fusionnée dans la branch develop
    --force-delete
        Supprimer une feature branch, même si elle n'a pas encore été fusionnée
        dans la branche develop

    -l, --log
    -d, --diff
        Afficher les modifications entre deux branches. L'option --log affiche
        les modifications dans l'ordre alors que --diff affiche les différences
        sous forme de diff. Les deux options peuvent être combinées et ont
        l'effet de 'git log -p'
        La branche comparée, s'il elle n'est pas spécifiée, est par défaut la
        branche courante. S'il s'agit d'une feature branch, elle est comparée à
        develop. S'il s'agit de la branche develop, elle est comparée à master."
}

projdir=
origin=origin
action=branch
merge_log=
merge_delete=1
force_delete=
log=
diff=
parse_opts "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -C:,--projdir: projdir= \
    -O:,--origin: origin= \
    -o,--offline UTOOLS_VCS_OFFLINE=1 \
    --online UTOOLS_VCS_OFFLINE= \
    -m,--merge action=merge \
    --merge-log merge_log=1 \
    -k,--keep merge_delete= \
    --delete action=delete \
    --force-delete '$action=delete; force_delete=1' \
    -l,--log '$action=diff; log=1' \
    -d,--diff '$action=diff; diff=1' \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

if [ -n "$projdir" ]; then
    cd "$projdir" || die
fi

git_ensure_gitvcs
if ! git_have_branch develop; then
    estepn "Configuration de la branche develop"
    git_ensure_branch develop master "$origin"
    [ $? -eq 2 ] && die "Impossible de créer la branche develop. Veuillez vérifier que la branche master existe"
fi

setx branch=git_get_branch
if [ "$action" == branch ]; then
    feature="$1"
    source="${2:-develop}"
    
    if [ -z "$feature" ]; then
        setx -a branches=list_feature_branches "$origin"
    
        if [ ${#branches[*]} -eq 0 ]; then
            # En l'absence de feature branch, basculer sur develop
            feature=develop
        else
            array_ins branches develop
            default_branch="$branch"
            array_contains branches "$default_branch" || default_branch=develop
            simple_menu feature branches -d "$default_branch" \
                -t "Basculer vers une feature branch" \
                -m "Veuillez choisir la branche vers laquelle basculer"
        fi
    fi
    
    # On est peut-être déjà sur la bonne branche
    if git_is_branch "$feature"; then
        if [ -z "$UTOOLS_VCS_OFFLINE" ]; then
            git_track_branch "$feature" "$origin"
        fi
        git_fast_forward "$feature" "" "$origin"
        exit 0
    fi
    
    # Créer/basculer vers une feature branch
    git_ensure_cleancheckout
    is_any_branch "$feature" develop feature || die "$release: ce n'est pas une feature branch"
    r=0
    if git_have_branch "$feature"; then
        git checkout "$feature" || r=$?
    elif git_have_rbranch "$feature" "$origin"; then
        git checkout "$feature" || r=$?
    else
        estepn "\
Vous allez créer la nouvelle feature branch ${COULEUR_VERTE}$feature${COULEUR_NORMALE}
à partir de la branche source ${COULEUR_BLEUE}$source${COULEUR_NORMALE}"
        ask_yesno "Voulez-vous continuer?" O || die

        git_ensure_branch "$feature" "$source" "$origin"
        [ $? -eq 2 ] && die "Impossible de créer la branche $feature. Veuillez vérifier que la branche $source existe"
        git checkout "$feature" || r=$?
    fi
    if [ "$r" -eq 0 ]; then
        # éventuellement fast-forwarder automatiquement
        git_fast_forward "$feature" "" "$origin"
    fi

    exit $?
fi

feature="$1"
if [ -n "$feature" ]; then
    is_feature_branch "$feature" || die "$feature: ce n'est pas une feature branch"
    git_have_branch "$feature" || die "$feature: branche introuvable"
elif is_feature_branch "$branch"; then
    feature="$branch"
fi

if [ "$action" == merge ]; then
    if [ -z "$feature" ]; then
        setx -a branches=list_feature_branches
        if [ ${#branches[*]} -eq 0 ]; then
            die "Aucune feature branch n'a été trouvée"
        elif [ ${#branches[*]} -eq 1 ]; then
            feature="${branches[0]}"
            estepn "Autosélection de $feature"
        else
            default_feature="$branch"
            array_contains branches "$default_feature" || default_feature="${branches[0]}"
            simple_menu feature branches -d "$default_feature" \
                -t "Choix de la feature branch" \
                -m "Veuillez choisir la branche"
        fi
    fi

    estepn "Intégration ${COULEUR_VERTE}$feature${COULEUR_NORMALE} --> ${COULEUR_BLEUE}develop${COULEUR_NORMALE}"
    ask_yesno "Voulez-vous continuer?" O || die

    # calculer la suite des modifications
    mergemsg="Intégration de la branche $feature"
    if [ -n "$merge_log" ]; then
        setx mergebase=git merge-base develop "$feature"
        setx modifs=git log --oneline "$mergebase..$feature"
        [ -n "$modifs" ] && mergemsg="$mergemsg
$modifs"
    fi

    git checkout develop || die
    git merge "$feature" -m "$mergemsg" --no-ff || die

    # mettre à jour la branche sur laquelle on se trouve
    setx branch=git_get_branch

    [ -n "$merge_delete" ] && action=delete
fi

if [ "$action" == delete ]; then
    if [ -z "$force_delete" ]; then
        # vérifier que la branche a été fusionnée
        git_is_merged "$feature" develop || die "Refus de supprimer la branche $feature: elle n'a pas été fusionnée dans develop"
    fi

    if [ "$branch" == "$feature" ]; then
        # si on est sur la branche en question, en sortir pour pouvoir la
        # supprimer
        git checkout develop || die
    fi

    estepi "Suppression de la branche locale"
    git branch -D "$feature"

    if git_have_remote "$origin"; then
        if [ -z "$UTOOLS_VCS_OFFLINE" ]; then
            estepi "Suppression de la branche distante"
            git push "$origin" ":$feature"
        elif git_have_rbranch "$feature" "$origin"; then
            eimportant "\
La branche $origin/$feature n'a plus lieu d'être, mais la configuration actuelle interdit de la supprimer.
Veuillez le faire manuellement avec la commande suivante:
    $(quoted_args git push "$origin" ":$feature")"
        fi
    fi
fi

if [ "$action" == diff ]; then
    if [ -n "$log" ]; then
        if [ -n "$feature" ]; then
            git log ${diff:+-p} develop.."$feature"
        else
            git log ${diff:+-p} master..develop
        fi
    elif [ -n "$diff" ]; then
        if [ -n "$feature" ]; then
            git diff develop.."$feature"
        else
            git diff master..develop
        fi
    fi
fi