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

function _git_update() {
    local branch
    local -a prbranches crbranches dbranches

    setx -a prbranches=git_list_rbranches
    git fetch -p "$@" || return
    setx -a crbranches=git_list_rbranches

    # vérifier s'il y a des branches distantes qui ont été supprimées
    for branch in "${prbranches[@]}"; do
        if ! array_contains crbranches "$branch"; then
            array_add dbranches "${branch#*/}"
        fi
    done
    if [ ${#dbranches[*]} -gt 0 ]; then
        setx -a branches=git_list_branches
        setx branch=git_get_branch

        eimportant "One or more distant branches where deleted"
        if git_check_cleancheckout; then
            einfo "Delete the obsolete local branches with these commands:"
        else
            ewarn "Take care of uncommitted local changes first"
            einfo "Then delete the obsolete local branches with these commands:"
        fi
        if array_contains dbranches "$branch"; then
            # si la branche courante est l'une des branches à supprimer, il faut
            # basculer vers develop ou master
            local swto
            if [ -z "$swto" ] && array_contains branches develop && ! array_contains dbranches develop; then
                swto=develop
            fi
            if [ -z "$swto" ] && array_contains branches master && ! array_contains dbranches master; then
                swto=master
            fi
            [ -n "$swto" ] && qvals git checkout "$swto"
        fi
        qvals git branch -D "${dbranches[@]}"
        return 1
    fi
    
    # intégrer les modifications des branches locales
    if ! git_check_cleancheckout; then
        setx branch=git_get_branch
        setx remote=git_get_branch_remote "$branch"
        setx rbranch=git_get_branch_rbranch "$branch" "$remote"
        pbranch="${rbranch#refs/remotes/}"
        if git merge -q --ff-only "$rbranch"; then
            enote "There are uncommitted local changes: only CURRENT branch were updated"
        fi
        return 0
    fi

    setx -a branches=git_list_branches
    restore_branch=
    for branch in "${branches[@]}"; do
        setx remote=git_get_branch_remote "$branch"
        setx rbranch=git_get_branch_rbranch "$branch" "$remote"
        pbranch="${rbranch#refs/remotes/}"
        [ -n "$remote" -a -n "$rbranch" ] || continue
        if git_is_ancestor "$branch" "$rbranch"; then
            if git_should_ff "$branch" "$rbranch"; then
                einfo "Fast-forwarding $branch -> $pbranch"
                git checkout -q "$branch"
                git merge -q --ff-only "$rbranch"
                restore_branch=1
            fi
        else
            if [ "$branch" == "$orig_branch" ]; then
                echo "* Cannot fast-forward CURRENT branch $branch from $pbranch
Try to merge manually with: git merge $pbranch"
            else
                echo "* Cannot fast-forward local branch $branch from $pbranch
You can merge manually with: git checkout $branch; git merge $pbranch"
            fi
        fi
    done
    [ -n "$restore_branch" ] && git checkout -q "$orig_branch"
    return 0
}

function git_update() {
    local cwd r
    setx cwd=ppath2 "$(pwd)" "$OrigCwd"
    etitle "$cwd"
    _git_update "$@"; r=$?
    eend
    return $r
}

chdir=
all=
Remote=
Autoff=1
Reset=ask
args=(
    "\
mettre à jour les branches locales

si la branche courante est une branche wip, écraser les modifications locales éventuelles après un avertissement.
sinon, ne mettre à jour la branche locale qu'en mode fast-forward"
    #"usage"
    -d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
    -a,--all all=1 "faire l'opération sur tous les sous-répertoires de BASEDIR qui sont des dépôts git"
    -o:,--remote Remote= "spécifier le remote depuis lequel faire le fetch"
    --autoff Autoff=1 "s'il n'y a pas de modifications locales, faire un fast-forward de toutes les branches traquées. c'est l'option par défaut."
    -l,--no-autoff Autoff= "ne pas faire de fast-forward automatique des branches traquées. seule la branche courante est mise à jour"
    --reset Reset=1 "écraser les modifications locales si la branche courante est une branche wip"
    -n,--no-reset Reset= "ne jamais écraser les modifications locales, même si la branche courante est une branche wip"
)
parse_args "$@"; set -- "${args[@]}"


setx OrigCwd=pwd
if [ -n "$chdir" ]; then
    cd "$chdir" || die
fi

if [ -n "$all" ]; then
    # liste de sous répertoires
    if [ $# -gt 0 ]; then
        # si on a une liste de patterns, l'utiliser
        setx -a dirs=ls_dirs . "$@"
    else
        dirs=()
        for dir in */.git; do
            [ -d "$dir" ] || continue
            dirs+=("${dir%/.git}")
        done
    fi
    setx cwd=pwd
    for dir in "${dirs[@]}"; do
        cd "$dir" || die
        git_update || die
        cd "$cwd"
    done
else
    # répertoire courant uniquement
    args=()
    isatty || args+=(--porcelain)
    git_update "${args[@]}"
fi