#!/bin/bash

##
## binaryDiv's dotfiles management script
## Version 0.3.1
##

usage() {
	cat <<- END_OF_HELPTEXT
	Usage: $(basename $0) COMMAND [...]
	Manage dotfiles via git.

	General commands:
	  help          print this help message

	Installation:
	  install       run this on first start: install dotfiles script in ~/bin, configure git, ...
	                (this will NOT create links for all dotfiles, though)

	Dotfile management:
	  ls [DIR]      list contents of .dotfiles directory (or DIR relative to it)
	  diff FILE     use vimdiff to compare ~/FILE to ~/.dotfiles/FILE
	  link FILE...  create a symlink from ~/FILE to ~/.dotfiles/FILE (multiple files possible)
	                (-q: be quiet, only print something if an error occurs)

	Synchronization:
	  git ARGS...   wrapper for git (all arguments are passed on to git)
	  pull          shortcut for git pull
	END_OF_HELPTEXT
}


# Define root dir for dotfiles management (defaults to $HOME, can be overridden
# with environment variables for debugging)
if [[ -z $DOTFILESROOT ]]; then
	DOTFILESROOT="$HOME"
fi

# Set variables
homedir="$DOTFILESROOT"
dotfilesdir="$DOTFILESROOT/.dotfiles"


# Get command
[[ $# -gt 0 ]] || { usage; exit 1; }
cmd=$1
shift

# Parse command
case "$cmd" in
	help|--help|-h)
		usage
		exit 1
	;;

	install)
		bin_source="$dotfilesdir/bin/dotfiles"
		bin_target="$homedir/bin/dotfiles"
		bin_dir="$homedir/bin"

		if [[ ! -e $bin_target ]]; then
			echo "* Installing dotfiles script in $bin_dir/"
			mkdir -pv "$bin_dir"
			ln -sr "$bin_source" "$bin_target" || exit 1
		elif [[ ! "$(realpath $bin_target)" -ef "$bin_source" ]]; then
			echo "! Warning: File $bin_target already exists but is NOT a link to $bin_source"
		fi

		if [[ ":$PATH:" != *":$bin_dir:"* ]]; then
			echo "! Warning: $bin_dir is not in your PATH."
		fi

		# Activate bash completion
		if [[ ! -e "$homedir/.bash_completion" ]]; then
			echo "* Installing user-defined bash completion"
			"$0" link -q .bash_completion &&
				echo "  Restart bash or run 'source $homedir/.bash_completion' to activate it now"
		fi

		echo "* Configuring git settings"
		git -C "$dotfilesdir" config merge.ff only
	;;

	ls)
		lsdir="$dotfilesdir"
		[[ -n $1 ]] && lsdir="$lsdir/$1"

		echo "$lsdir:"
		ls -lAh --color=auto "$lsdir"
	;;

	# TODO: Command 'status' or 'linkstatus' to show which files are linked and which are not

	diff)
		[[ -n $1 ]] || { echo "$(basename $0) $cmd: Missing argument."; exit 1; }
		file_A="$homedir/$1"
		file_B="$dotfilesdir/$1"

		if [[ "$(realpath "$file_A")" -ef "$file_B" ]]; then
			echo "$file_A is a link to $file_B"
		else
			vimdiff "$file_A" "$file_B"
		fi
	;;

	link)
		if [[ $1 = '-q' ]]; then
			QUIET=1
			shift
		fi

		[[ -n $1 ]] || { echo "$(basename $0) $cmd: Missing argument."; exit 1; }

		for filename in "$@"; do
			file_home="$homedir/$filename"
			file_dotfiles="$dotfilesdir/$filename"

			if [[ ! -e $file_dotfiles ]]; then
				echo "! $file_dotfiles: target file does not exist"
				exit 1
			elif [[ -e $file_home ]]; then
				if [[ ! "$(realpath "$file_home")" -ef "$file_dotfiles" ]]; then
					echo "! $file_home already exists but is NOT a link to $file_dotfiles, please fix manually"
					exit 1
				fi
			else
				[[ $QUIET ]] || echo "* Creating link $file_home -> $file_dotfiles"
				ln -sr "$file_dotfiles" "$file_home" || exit 1
			fi
		done
	;;
	
	git)
		git -C "$dotfilesdir" "$@"
	;;

	pull)
		git -C "$dotfilesdir" pull "$@"
	;;

	bash-completion)
		cat <<- 'END_OF_BASHCOMPLETION'
		_dotfiles_filenames() {
			compopt -o filenames
			files=($(compgen -f -X '*/@(.|..|.git)' .dotfiles/$cur))
			COMPREPLY=(${files[@]#.dotfiles/})
		}
		_dotfiles() {
			COMPREPLY=()
			local cur="${COMP_WORDS[COMP_CWORD]}"
			local commands="help install ls diff link git pull"
			local gitcommands="add commit diff fetch log pull push rebase status"

			if [[ $COMP_CWORD -eq 1 ]]; then
				COMPREPLY=($(compgen -W "$commands" -- $cur))
			else
				case "${COMP_WORDS[1]}" in
					ls|diff)
						[[ $COMP_CWORD -eq 2 ]] && _dotfiles_filenames
					;;

					link)
						_dotfiles_filenames
					;;

					git)
						if [[ $COMP_CWORD -eq 2 ]]; then
							COMPREPLY=($(compgen -W "$gitcommands" -- ${cur}))
						else
							_dotfiles_filenames
						fi
					;;
				esac
			fi
		}

		complete -F _dotfiles dotfiles
		END_OF_BASHCOMPLETION
	;;

	*)
		echo "Unknown command '$cmd', use 'help' to show all commands."
		exit 1
	;;
esac

