#!/bin/bash
# set -x 

source ./log_helpers
source ./general_utils


# if [ ${git_helpers_sourced:-1} = "1" ]; then
#    readonly git_helpers_sourced=${BASH_SOURCE[0]}

readonly repository_already_up_to_date=2

#
exec_git_command () {
    local func="${FUNCNAME[0]}"
    log_debug "$func:${LINENO} exec-ing [$*]"
    
    local __git_result=$(exec_process_substitution $*)
    log_debug "$func:${LINENO} result=$__git_result"

    printf '%s' "$__git_result"
}

# 
latest_commit () {
    local func="${FUNCNAME[0]}"
    # git reflog -> 46c5896 HEAD@{0}: commit: Made update_helpers executable
    local c=$(git reflog | grep "HEAD@{0}" | cut -d" " -f1)
    if ! [ -z "$c" ]; then
        if grep -qE "^[[:xdigit:]]{6,}$" <<< $c; then
            log_debug "$func:${LINENO} commit -> $c"
            printf "%s\n" $c
        else
            log_crit "$func:${LINENO} wrong format for commit c=$c"
        fi
    else 
        log_crit "$func:${LINENO} 'git reflog' result empty"
    fi
}

# fallback if something went wrong: revert to last valid commit
revert_to_commit_before_pull () {
    local func="${FUNCNAME[0]}"
    if ! [ -z "$commit_before_pull" ]; then
        if grep -qE "^[[:xdigit:]]{6,}$" <<< $commit_before_pull; then
            `git reset --hard "$commit_before_pull"`
            if [ $? -eq 0 ]; then
                log_info "$func: git reset --hard $commit_before_pull"
                return 0
            fi
            log_crit "$func: 'git reset --hard $commit_before_pull' failed!"
        fi
        log_crit "$func: wrong format for commit_before_pull"
    fi
    log_crit "$func: empty commit_before_pull"
    return 1
}
# revert_to_commit_before_pull

# clone the customer repository in ./UpdateController/workspace.
# this is done only once.
clone_customer_repository () {
    local func="${FUNCNAME[0]}"
    if [ "$PWD" = "$working_directory" ]; then
        if ! [[ -d $workspace_dir ]]; then
            { mkdir -p ./$workspace_dir; }
        fi
        # check if the directory is empty. If so, clone the
        # customer repository
        if ! find ./$workspace_dir -mindepth 1 -maxdepth 1 | read; then
            log_debug "$func:${LINENO} cloning ${1} ..."
            if { cd ./$workspace_dir ; }; then
                $(exec_git_command git clone "$1")
                if [ $? -eq 0 ]; then
                    log_debug "$func:${LINENO} cloning ${1} done"
                    cd - ; return 0
                fi
                cd -
            fi
        else
            # the directory is not empty, so we assume the
            # customer-repository has been cloned already
            if ! [[ -d ./${workspace_dir}/$customer_id ]]; then
                log_fatal "$func:${LINENO} "\
                    "wrong repository: $(ls -d './${workspace_dir}/*')"
            else
                local __m="./${workspace_dir}/$customer_id exists"
                log_debug "$func:${LINENO} $__m"
                return 0
            fi
        fi
    fi
    return 1
}
# clone_customer_repository ->
# https://git.mimbach49.de/GerhardHoffmann/customer_281.git

cd_customer_repository () {
    # has to be called in ./UpdateController
    local func="${FUNCNAME[0]}"
    current_dir=${PWD##*/}
    current_dir="./${current_dir:-/}"
    if [ "$current_dir" = "./UpdateController" ]; then
        repository_dir="./workspace/${customer_id}"
        if ! [[ -d "$repository_dir" ]]; then
            log_crit "$func:${LINENO}: $repository_dir does not exist!"
            return 1
        fi
        
        if ! { cd $repository_dir; } ; then
            log_crit "$func:${LINENO}: cannot cd to $repository_dir!"
            return 1
        fi

        log_debug "$func:${LINENO}: cd to $repository_dir!"
        return 0
    fi
    return 1
}

cd_home () {
    if cd - &>/dev/null ; then
        return 0
    fi
    return 1
}

pull_customer_repository () {
    # has to be called in ./UpdateController
    local func="${FUNCNAME[0]}"

    if ! cd_customer_repository ; then
        return 1
    fi

    local commit_before_pull=$(latest_commit)
    if [ -z $commit_before_pull ]; then
        cd_home ; return 1
    fi

    log_debug "$func:${LINENO}: commit_before_pull=$commit_before_pull"
   
    local git_result=$(exec_git_command 'git pull')

    if [ -z "$git_result" ]; then
        log_warn "$func:${LINENO}: git result empty" ; cd_home;
        return 1
    fi

    # see 'man -Pless\ +/parameter/pattern/string/bash'
    git_result=${git_result//[$'\r\n\t']/ }

    log_debug "$func:${LINENO} git-pull-result=${git_result}"

    if grep -qE "^Already\s+\up\s+\to\s+date.*$" <<< $git_result; then
        log_warn "$func:${LINENO}: repository $PWD already up to date."
        read $1 <<< 'yes'
        cd_home ; return 1
    fi

    local commit_after_pull=$(latest_commit)
    if [ -z $commit_after_pull ]; then
        cd_home ; return 1
    fi
    
    log_debug "$func:${LINENO}: commit_after_pull=$commit_after_pull"

    # Note: # 'git pull' is a 'git fetch' followed by a 'git merge'.
    # Here's the fetch portion:
    #
    # remote: Counting objects: 11, done.
    # remote: Compressing objects: 100% (5/5), done.
    # remote: Total 7 (delta 2), reused 0 (delta 0)
    #
    # At this point, you've told the remote what you want.
    # It finds all the objects it needs to give you,
    # compresses them for faster transfer over the network,
    # and then reports what it's sending you.
    # 
    # Unpacking objects: 100% (7/7), done.
    # 
    # You receive the pack (set of compressed objects) and unpack it.
    #
    # From ssh://my.remote.host.com/~/git/myproject
    # * branch            master     -> FETCH_HEAD

    # You've fetched the branch 'master' from the given remote;
    # the ref FETCH_HEAD now points to it.
    # Now we move on to the merge - precisely, git will merge
    # FETCH_HEAD (the remote's master branch) into your current branch
    # (presumably master).
    #
    #######################################################################
    # here starts "message"
    # 
    # Updating 9d447d2..f74fb21
    # Fast forward
    #
    # It turns out that you haven't diverged from the remote's master branch,
    # so the merge is a fast-forward (a trivial merge where it simply moves
    # you forward in the history).
    #
    # Git notes the original position of your master branch (9d447d2)
    # and the new position (f74fb21) it's been fast-forwarded to.
    # If you had diverged from the remote's master branch,
    # you'd see the output of a recursive merge here - Merge made
    # by recursive, possibly along with some Auto-merged <file>
    # and (oh no!) merge conflicts!
    #
    # szeged/1/1/etc/psa_config/device.conf | 13 +++++++------
    # szeged/update.conf                    |  2 +-
    # 2 files changed, 8 insertions(+), 7 deletions(-)
    #  
    # Finally, it shows you the diffstat between the original and post-merge
    # position of your master branch;
    # this is basically what you'd get from
    #
    # git diff --stat master@{1} master.
    # 

    update_commit="${commit_before_pull}..${commit_after_pull}"
    if ! grep -qE ".*Updating\s+${update_commit}.*?" <<< $git_result; then
        log_crit "$func:${LINENO}: no $update_commit in [ $git_result ]"
        cd_home ; return 1
    fi

    cd_home ; return 0
}
# pull_customer_repository customer_281

changed_file_names () {
    local func="${FUNCNAME[0]}"
    if  cd_customer_repository ; then
        local git_res=$(exec_git_command 'git diff --stat master@{1} master')
        git_res=${git_res//[$'\r\n\t']/ }
        log_debug "$func:${LINENO}: git_res=$git_res"
        local file_names=""
        local known_files=(update.conf current.conf emp.conf)
        known_files=(${known_files[@]} device.conf printer.conf opkg_commands) 
        for f in ${known_files[@]} ; do 
            if grep -qE ".*/${f}\s+.*" <<< $git_res; then
                if ! [ -z $file_names ]; then
                    file_names="$f $file_names"
                else
                    file_names="$f"
                fi
            fi
        done    

        cd_home; log_debug "$func:${LINENO}: file_names=$file_names" ;
        printf '%s' "$file_names" 
    else
        log_crit "$func:${LINENO}: cannot cd to $customer_repository "\
            "while in $PWD"
    fi
}
# fi