#!/bin/bash

# Copyright (C) 2018, 2019 Lee C. Bussy (@LBussy)

# This file is part of LBussy's BrewPi Script Remix (BrewPi-Script-RMX).
#
# BrewPi Script RMX is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# BrewPi Script RMX is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BrewPi Script RMX. If not, see <https://www.gnu.org/licenses/>.

# Declare this script's constants/variables
declare SCRIPTPATH GITROOT wwwPath toolPath didUpdate quick
didUpdate=0
# Declare /inc/const.inc file constants
declare THISSCRIPT SCRIPTNAME VERSION GITROOT GITURL GITPROJ PACKAGE
# Declare /inc/asroot.inc file constants
declare HOMEPATH REALUSER
# Declare my constants/variables
declare url
url="https://raw.githubusercontent.com/brewpi-remix/brewpi-script-rmx/THISBRANCH/utils/doUpdate.sh"

############
### Init
############

init() {
    # Change to current dir (assumed to be in a repo) so we can get the git info
    pushd . &> /dev/null || exit 1
    SCRIPTPATH="$( cd "$(dirname "$0")" || exit 1 ; pwd -P )"
    cd "$SCRIPTPATH" || exit 1 # Move to where the script is
    GITROOT="$(git rev-parse --show-toplevel)" &> /dev/null
    if [ -z "$GITROOT" ]; then
        echo -e "\nERROR: Unable to find repository, did you not run as root or from" > /dev/tty
        echo -e "brewpi directory?" > /dev/tty
        popd &> /dev/null || exit 1
        exit 1
    fi
    
    # Get project constants
    # shellcheck source=/dev/null
    . "$GITROOT/inc/const.inc" "$@"
    
    # Get error handling functionality
    # shellcheck source=/dev/null
    . "$GITROOT/inc/error.inc" "$@"
    
    # Get help and version functionality
    # shellcheck source=/dev/null
    . "$GITROOT/inc/asroot.inc" "$@"
    
    # Get help and version functionality
    # shellcheck source=/dev/null
    . "$GITROOT/inc/help.inc" "$@"
    
    # Get network test functionality
    # shellcheck source=/dev/null
    . "$GITROOT/inc/nettest.inc" "$@"
    
    # Get config reading functionality
    # shellcheck source=/dev/null
    . "$GITROOT/inc/config.inc" "$@"
}

############
### Create a banner
############

banner() {
    local adj
    adj="$1"
    echo -e "\n***Script $THISSCRIPT $adj.***" > /dev/tty 
}

############
### Function: whatRepo
### Argument: String representing a directory
### Return: Location of .git within that tree, or blank if there is none
############

function whatRepo() {
    local thisRepo thisReturn
    thisRepo="$1"
    if [ ! -d "$thisRepo" ]; then
        return # Not a directory
    elif ! ( cd "$thisRepo" && git rev-parse --git-dir &> /dev/null ); then
        return # Not part of a repo
    fi
    pushd . &> /dev/null || exit 1
    cd "$thisRepo" || exit 1
    thisReturn=$(git rev-parse --show-toplevel)
    if [ ! -d "$thisReturn" ]; then
        thisReturn=""
    fi
    popd &> /dev/null || exit 1
    echo "$thisReturn"
}

############
### Function: updateRepo
### Argument: String representing a directory
### Return: Success
############

# Checks for proper repo, tries to update from GitHub if it is
function updateRepo() {
    local thisRepo
    thisRepo="$1"
    # First check to see if arg is a valid repo
    gitLoc=$(whatRepo "$thisRepo")
    if [ -n "$gitLoc" ]; then
        # Store the current working directory
        pushd . &> /dev/null || exit 1
        cd "$thisRepo" || exit 1
        # See if we can get the active branch
        active_branch=$(git symbolic-ref -q HEAD)
        retval=$?
        if [ $retval -eq 0 ]; then
            active_branch=${active_branch##refs/heads/}
            # Make sure we have all remote branches
            git remote set-branches origin '*'
            git fetch
            # Check local against remote
            changes=$(git log HEAD..origin/"$active_branch" --oneline)
            if [ -z "$changes" ]; then
                # no changes
                echo -e "\n$thisRepo is up to date."
                popd &> /dev/null || exit 1
                return 0
            else
                echo -e "\n$thisRepo is not up to date, updating from GitHub:"
                git fetch --all
                git pull --all
                retval=$?
                if [ $retval -ne 0 ]; then
                    # Not able to make a pull, probably because of changed local files
                    echo -e "\nAn error occurred during the git pull. Please update this repo manually:"
                    echo -e "$thisRepo"
                    echo -e "\nIf this is a result of having made local changes, you can stash your local"
                    echo -e "changes and then pull the current GitHub repo with:"
                    echo -e "'cd $thisRepo; sudo git stash; sudo git pull'"
                    echo -e "\nUnder normal conditions you should never see this message.  If you have no"
                    echo -e "idea what is going on, restarting the entire process or reinstalling should"
                    echo -e "reset things to normal."
                    popd &> /dev/null || exit 1
                    return 1
                else
                    ((didUpdate++))
                fi
            fi
        else
            # No local repository found
            echo -e "\nNo local repository found (you should never see this error.)"
            popd &> /dev/null || exit 1
            return 1
        fi
        # Back to where we started
        popd &> /dev/null || exit 1
        return 0
    else
        echo -e "\nNo valid repo passed to function (repo = '$thisRepo')."
    fi
}

############
### Set up repos
############

getrepos() {
    # Get app locations based on local config
    wwwPath="$(getVal wwwPath "$GITROOT")"
    toolPath="$(whatRepo "$(eval echo "/home/$(logname 2> /dev/null)/brewpi-tools-rmx/")")"
    if [ ! -d "$toolPath" ] || [ -z "$toolPath" ]; then
        toolPath="$(whatRepo "/home/pi/brewpi-tools-rmx/")"
        if [ ! -d "$toolPath" ]; then
            echo -e "\nWARN: Unable to find a local BrewPi-Tools-RMX repository." > /dev/tty
        fi
    fi
}

############
### Check for Updated doUpdate Script
############

updateme() {
    # Download current doUpdate.sh to a temp file and run that instead
    local branch
    branch=$(git branch | grep \* | cut -d ' ' -f2)
    url="${url/THISBRANCH/$branch}"
    echo -e "\nDownloading current version of this script." > /dev/tty 
    cd "$SCRIPTPATH" && { curl -s "$url" -o "tmpUpdate.sh"; cd - &> /dev/null || die; } > /dev/tty 
    chown brewpi:brewpi "$SCRIPTPATH/tmpUpdate.sh" > /dev/tty 
    chmod 770 "$SCRIPTPATH/tmpUpdate.sh" > /dev/tty 
    echo -e "\nExecuting current version of script." > /dev/tty 
    eval "bash $SCRIPTPATH/tmpUpdate.sh $*" > /dev/tty 
}

############
### Update repo URL
############

doRepoUrl() {
    local currrentUrl newUrl currentRepo
    currentRepo="$1"
    pushd . &> /dev/null || die # Store current directory
    cd "$currentRepo" || die # Move to where the script is
    currrentUrl="$(git config --get remote.origin.url)"
    newUrl="${currrentUrl/lbussy/brewpi-remix}"
    if [ ! "$newUrl" == "$currentUrl" ]; then
        # Repo has moved to a new org, update to current url
        git remote set-url origin "$newUrl"
    fi
    popd &> /dev/null || die # Move back to where we started
}

############
### Process Updates
############

process() {
    local doRepo arg
    doRepo="$1"
    pushd . &> /dev/null || die # Store current directory
    cd "$(dirname "$(readlink -e "$0")")" || die # Move to where the script is
    # Update repo as necessary
    echo -e "\nChecking $doRepo for necessary updates." > /dev/tty 
    doRepoUrl "$doRepo" || warn
    updateRepo "$doRepo" || warn
    popd &> /dev/null || die # Move back to where we started
}

############
### Do cleanup
############

cleanup() {
    # If we did a pull:
    #    - Run apt to check packages
    #    - Run doCleanup.sh to clean things up
    #    - Restart apache2 and chamber
    local chamber
    if [ "$didUpdate" -ge 1 ]; then
        if [ ! "$quick" == "true" ]; then
            # Install/update all dependencies and clean local apt cache
            "$GITROOT/utils/doDepends.sh"
        fi
        # Cleanup *.pyc files and empty dirs, update daemons, do perms
        "$GITROOT/utils/doCleanup.sh"
        chamber="$(getVal "chamber" $SCRIPTPATH)"
        chamber=$(echo "$chamber" | tr -d \")
        if [ -z "$chamber" ] || [[ "$chamber" -eq "__UNDEFINED__" ]]; then
            echo -e "\nRestarting BrewPi."
            systemctl restart brewpi
        else
            echo -e "\nRestarting BrewPi chamber $chamber."
            systemctl restart "$chamber"
        fi
        echo -e "\nRestarting Apache2."
        systemctl restart apache2
    fi
}

############
### Flash controller
############

flash() {
    local yn branch
    branch==$(git branch | grep \* | cut -d ' ' -f2)
    if [ ! "$branch" == "master" ]; then
        branch="--beta"
    else
        branch=""
    fi
    echo "" > /dev/tty 
    read -rp "Do you want to flash your controller now? [y/N]: " yn  < /dev/tty
    case "$yn" in
        [Yy]* ) eval "python3 -u $SCRIPTPATH/utils/updateFirmware.py $branch" ;;
        * ) ;;
    esac
}

############
### Main function
############

main() {
    init "$@" # Init and call supporting libs
    const "$@" # Get script constants
    if [ "$THISSCRIPT" == "tmpUpdate.sh" ]; then
        # Delete the temp script before we do an update
        rm "$SCRIPTPATH/tmpUpdate.sh"
        getrepos "$@" # Get list of repositories to update
        if [ -d "$toolPath" ]; then process "$toolPath"; fi # Check and process updates
        if [ -d "$SCRIPTPATH" ]; then process "$SCRIPTPATH"; fi # Check and process updates
        if [ -d "$wwwPath" ]; then process "$wwwPath"; fi # Check and process updates
        cleanup # Update dependencies if we did a git update
        flash # Offer to flash controller
    else
        arg="$1"
        if [[ "${arg//-}" == "q"* ]]; then quick=true; else quick=false; fi
        help "$@" # Process help and version requests
        asroot # Make sure we are running with root privs
        THISSCRIPT="doUpdate.sh"
        banner "starting"
        # Get the latest doUpdate.sh script and run it instead
        updateme "$@"
        THISSCRIPT="doUpdate.sh"
        banner "complete"
    fi
}

main "$@" && exit 0
