# Functions used for interactive installation of new changes to running system
# vim: ft=sh

ask() {
	if $FORCE; then
		echo -e "\e[1;34m$1\e[0m"
		# Fall trough with 0 exit (always yes)
	else
		echo -e -n "\e[1;34m$1? (Y/n) \e[0m"
		read
		[[ $REPLY =~ ^[Yy]?$ ]]
	fi
}

dodiff() {
	if [ -d "$2" ]; then
		# If we just copying some file to directory
		OUT=$2/$(basename "$1")
	else
		OUT=$2
	fi
	if ! [ -f "$OUT" ]; then
		echo -e "\e[1;33mNot installed:\e[0m $1 => $OUT"
		if ask "Install?"; then
			doinst "$1" "$OUT"
		fi
		return
	fi
	if cmp "$1" "$OUT" >/dev/null 2>&1; then
		echo -e "\e[1;32mNo difference detected:\e[0m $OUT"
		return
	fi
	if $FORCE; then
		doinst "$1" "$OUT"
	else
		vimdiff "$1" "$OUT"
	fi
}

# Managing two git trees with master has small inconvenience that git allows only
# single branch checkout in all work trees, so as it sets now git will execute all
# commands not on deployed tree but on tree in this repository, so we need specify
# work tree on command line every time we want target deployed work tree.
gitrepo_relink() {
	local GITD="gitdir: $PWD/.git$(sed "s/^gitdir: [./]*git//" "$1")"
	# We check that we are pointing to correct path just because of making message correct
	if ! grep -q "$GITD" "$2"; then
		echo -e "\e[1;34mPointing git repository $2 to this repository\e[0m"
		echo "$GITD" > "$2"
	fi
	# else probably not a git repository or who knows.
}

checkdiff() {
	# Iterate trough source directory but ignore any git repositories
	# Note that it's design decision to not iterate trough target directory.
	if [ -d "$1" ]; then
		# This is check if we have correct inst command basically. If it is
		# directory than it have to have trailing slash to ensure that no
		# additional directory is created.
		if ! echo "$1" | grep -qE '/$'; then
			echo -e "\e[1;31mERROR: Directory without trailing slash detected:\e[0m $1"
			exit 1
		fi
		# Got trough all files ignoring git repositories
		for f in `find "$1" \( -type d -exec test -e '{}'/.git \; \) -prune -o -type f -print`; do
			F="${f#$1}"
			dodiff "$1/$F" "$2/$F"
		done
		# Check if we have all directories ignoring those in git repositories
		for d in `find "$1" -type d -print -exec test -e '{}'/.git \; -prune`; do
			D="${d#$1}"
			if [ ! -d "$2/$D" ]; then
				echo -e "\e[1;33mDirectory not installed:\e[0m $1/$D => $2/$D"
				if ask "Install?"; then
					doinst "$1/$D/" "$2/$D"
				fi
			fi
		done
		# Now checkout git repositories
		for g in `find "$1" -type d -exec test -e '{}'/.git \; -print -prune`; do
			G="$2/${g#$1}"
			gitrepo_relink "$g/.git" "$G/.git" # Always reling .git just to be sure
			PREV="$(pwd)"
			cd "$G"
			# Check if we have any change at all
			if git --work-tree=. diff --exit-code -s; then
				echo -e "\e[1;32mNo difference detected in git:\e[0m $G"
			else
				echo -e "\e[0;32mCheckout of git repository:\e[0m $G"
				# Checkout all files to HEAD
				git --work-tree=. checkout -f HEAD
				# Update all submodules
				git --work-tree=. submodule update --recursive
			fi
			cd "$PREV"
		done
	else
		dodiff "$1" "$2"
	fi
}

doinst() {
	echo -e "\e[1;34mrsync -rlpt $1 $2\e[0m"
	rsync -rlpt $1 $2
	# Now edit all .git files in target directory
	for g in `find "$1" -name '.git' -type f`; do
		gitrepo_relink "$g" "$2/${g#$1}"
	done
}

inst() {
	if [ -e "$2" ]; then
		# If output exists, execute diff instead
		checkdiff $1 $2
		return
	fi
	doinst $1 $2
}

# gpg encrypted install
ginst() {
	if [ -z "$PASS" ]; then
		PASS="$(gpg --batch --decrypt pass.gpg)"
	fi
	# TODO probably we should be sure that file will be always removed
	local TMP="$(mktemp myconfigs.XXXXXXXXXX)"
	gpg --batch --passphase "$PASS" --output "$TMP" --decrypt "$1"
	inst "$TMP" "$2"
	gpg --batch --passphase "$PASS" --output "$1" --encrypt "$TMP"
}