#! /bin/bash

ACTIONS=''
for arg in $@; do
    case "$arg" in
        pull|push|commit)
            ACTIONS="$ACTIONS $arg"
            ;;
        *)
            GIT_SVN_CONFIG=$arg
            ;;
    esac
done
BATCH_MODE=0
[ ! -z "$ACTIONS" ] && BATCH_MODE=1
GIT_SVN_CONFIG=${GIT_SVN_CONFIG:-".git-svn-config"}

RED="\033[0;31m"
RESET="\033[0m"

function error () {
    echo -e " $1 => ${RED}FAILURE${RESET}"  && exit 1
}

function say () {
    [ $BATCH_MODE == 0 ] && echo -e "$1"
    return 0
}

[ -e $GIT_SVN_CONFIG ] || error "$GIT_SVN_CONFIG does not exists!"
source ./$GIT_SVN_CONFIG

[ ! -z "$PRJ" ] || error "PRJ variable is not defined"
[ ! -z "$SVN_URL" ] || error "SVN_URL variable is not defined"
[ ! -z "$BRANCHES_TO_TRACK" ] || error "BRANCHES_TO_TRACK variable is not defined"

LOCAL_REPO=${LOCAL_REPO:-"local"}
LOCAL_DIR=${LOCAL_DIR:-"$(pwd)/${PRJ}"}
SVN_SUFFIX=_svn
SVN_CLONE_REPO=${SVN_CLONE_REPO:-"svn_clone"}
SVN_CLONE_DIR=${SVN_CLONE_DIR:-"$(pwd)/${PRJ}${SVN_SUFFIX}"}

URL_COLOR="\033[0;34m"
LRC="\033[0;33m"    # LOCAL REPO COLOR
LBC="\033[0;36m"    # LOCAL BRANCH COLOR
SRC="\033[0;35m"    # SVN CLONE REPO COLOR
SBC="\033[0;32m"    # SVN CLONE BRANCH COLOR
DSBC="\033[0;37m"   # DISTANT SVN BRANCH COLOR

function ask_ok () {
    [ $BATCH_MODE == 1 ] && return 0
    echo -e -n "$1${RESET}[${RED}Y${RESET}n] : "
    read  OK
    if [ "$OK" = "" -o "$OK" = "y" -o "$OK" = "Y" ]; then
        return 0
    fi
    say "${RED}abort${RESET}" && return 1
}

function create_svn_clone () {
    say "** clone from ${URL_COLOR}${SVN_URL}${RESET}" && cd ${SVN_CLONE_DIR%/*} && git svn clone ${SVN_URL} -T trunk -b branches -t tags ${SVN_CLONE_DIR} || error
    cd ${SVN_CLONE_DIR}
    for branch in $BRANCHES_TO_TRACK; do
        say "** checkout ${DSBC}${branch}${RESET} in ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}${SVN_SUFFIX}${RESET}" && \
            git checkout $branch -b ${branch}${SVN_SUFFIX}  || error
    done
    say "** remove master branch" && git branch -D master || error
    say "** add ${LRC}${LOCAL_DIR}${RESET} as repo ${LRC}${LOCAL_REPO}${RESET}" && git remote add ${LOCAL_REPO} ${LOCAL_DIR} || error
}

function create_local_repo () {
    say "** git init ${LRC}${LOCAL_DIR}${RESET}" && git init ${LOCAL_DIR}|| error
    say "** cd ${LRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error
    say "** add ${SRC}${SVN_CLONE_DIR}${RESET} as repo ${SRC}${SVN_CLONE_REPO}${RESET}" && git remote add ${SVN_CLONE_REPO} ${SVN_CLONE_DIR} || error
    say "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error
    for branch in $BRANCHES_TO_TRACK; do
        say "** checkout ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}${SVN_SUFFIX}${RESET} to ${SBC}${branch}${RESET}" && \
            git checkout ${SVN_CLONE_REPO}/${branch}${SVN_SUFFIX} -b ${branch}  || error
    done
}

function svn_fetch () {
    say "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error
    say "** fetch from ${URL_COLOR}${SVN_URL}${RESET}" && git svn fetch || error
    BRANCHES=$(git for-each-ref --format="%(refname:short)" refs/heads/)
    for branch in $BRANCHES; do
        say "** rebase ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${branch}${RESET}" && git checkout $branch && git svn rebase || error
    done
    say "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error
    say "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error
}

function push_to_svn_clone () {
    say "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error
    say "** fetch ${LRC}${LOCAL_REPO}${RESET}" && git fetch ${LOCAL_REPO} || error
    say "** checkout ${SBC}${SVN_B}${RESET}" && git checkout ${SVN_B} || error
    say "** rebase ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET} within ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET}" && \
        git rebase ${LOCAL_REPO}/${LOCAL_B} || error
    say "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error
    say "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error
}

function svn_dcommit () {
    say "** cd ${SRC}${SVN_CLONE_DIR}${RESET}" && cd ${SVN_CLONE_DIR} || error
    say "** checkout ${SBC}${SVN_B}${RESET}" && git checkout ${SVN_B} || error
    say "** rebase ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET}" && git svn rebase || error
    say "** dcommit ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET} to ${URL_COLOR}${SVN_URL}${RESET}" && git svn dcommit
}

function pull_from_svn_clone () {
    #say "** cd ${SRC}${LOCAL_DIR}${RESET}" && cd ${LOCAL_DIR} || error
    #say "** fetch ${SRC}${SVN_CLONE_REPO}${RESET}" && git fetch ${SVN_CLONE_REPO} || error
    #say "** merge ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET} within ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET}" && git merge ${SVN_CLONE_REPO}/${SVN_B} || error
    say "To do so :"
    say "  ${LRC}- save your current work      ${SRC}$ git stash save NAME${RESET}"
    say "  ${LRC}- leave your current branch   ${SRC}$ git checkout ANOTHER_BRANCH${RESET}"
    say "  ${LRC}- delete your branch          ${SRC}$ git branch -D ${LOCAL_B}${RESET}"
    say "  ${LRC}- checkout your branch        ${SRC}$ git checkout ${SVN_CLONE_REPO}/${LOCAL_B}${SVN_SUFFIX} -b ${LOCAL_B}${RESET}"
    say "  ${LRC}- apply your current work     ${SRC}$ git stash pop/apply${RESET}"
}

if [ ! -d ${SVN_CLONE_DIR} ]; then
    ask_ok "clone svn repository ${URL_COLOR}${SVN_URL}${RESET} to ${SRC}${SVN_CLONE_DIR}${RESET} " && create_svn_clone
fi
if [ ! -d ${LOCAL_DIR} ]; then
    ask_ok "create local repository within ${LRC}${LOCAL_DIR}${RESET} " && create_local_repo
fi

cd ${LOCAL_DIR} 2>/dev/null || error "${LOCAL_DIR} does not exists"
LOCAL_B=$(git branch |grep '*' | gawk '{print $2;}') || error "unable to list local branches"
LOCAL_HEAD=$(git log --pretty="format:%H" HEAD~1..) || error "unable to read local head"
say "** ${LRC}${LOCAL_REPO}${RESET} current branch is ${LBC}${LOCAL_B}${RESET} head ${RED}${LOCAL_HEAD}${RESET}"
cd ${SVN_CLONE_DIR} 2>/dev/null || error "${SVN_CLONE_DIR} does not exists"
SVN_B=${LOCAL_B}_svn
git checkout ${SVN_B}
SVN_HEAD=$(git log --pretty="format:%H" HEAD~1..) || error "unable to read local head"
say "** ${LRC}${SVN_CLONE_REPO}${RESET} corresponding branch is ${LBC}${SVN_B}${RESET} head ${RED}${SVN_HEAD}${RESET}"
cd ${LOCAL_DIR}

while [ -z "$ACTIONS" ]; do
    say "\nOptions :"
    say " # 1) ${RED}fetch svn${RESET} and update branches within ${SRC}${SVN_CLONE_DIR}${RESET}"
    say " # 2) ${RED}push${RESET} ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET} within ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET}"
    say " # 3) ${RED}push${RESET} ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET} to ${URL_COLOR}${SVN_URL}${RESET}"
    say " # 4) ${RED}pull${RESET} ${SRC}${SVN_CLONE_REPO}${RESET}/${SBC}${SVN_B}${RESET} within ${LRC}${LOCAL_REPO}${RESET}/${LBC}${LOCAL_B}${RESET}"
    say " # q) ${RED}QUIT${RESET}"
    echo -n -e "\nyour choice : "
    read CHOICE
    echo ""
    case $CHOICE in
        q)
            exit 0
            ;;
        1)
            svn_fetch
            ;;
        2)
            push_to_svn_clone
            ;;
        3)
            svn_dcommit
            ;;
        4)
            pull_from_svn_clone
            ;;
    esac
done

if [ ! -z "$ACTIONS" ]; then
    for action in $ACTIONS; do
        if [ "$action" == "pull" ];  then
            svn_fetch
        elif [ "$action" == "push" ];  then
            push_to_svn_clone
        elif [ "$action" == "commit" ];  then
            svn_dcommit
        fi
    done
fi