#! /usr/bin/env bash
#
# Salt's bootstrap script
# Copyrithgt (C) 2018 salt <salt@lap-th-e560-0>
#
# Distributed under terms of the MIT license
#

# shellcheck disable=1117

## Helper functions
log() {
	[ -z ${1+x} ] && return 1
	out=1
	[ -z ${2+x} ] || out="$2"
	col_message="\e[39m"
	[ "$out" -gt "1" ] && col_message="\e[31m"
	[ "$out" -lt "1" ] && out=1 && col_message="\e[37m"
	printf "\e[94m%s\e[0m: %b%s\e[0m\n" \
		"$name" \
		"$col_message" \
		"$1" >&${out}
}
validatedep() {
	if ! command -v "$1" > /dev/null 2>&1; then
		return 1
	fi
	return 0
}
help() {
	cat << EOF
Usage: $name [OPTION]
Bootstrap a git repository as a bare repo, also perform some bootstrap tasks.
  -d			Bootstrap directory. Defaults to ~.
  -r			Target repository. Defaults to
			gitlab.com/rehashedsalt/home
  -l			File to log command output to. Defaults to
			replicate.log
EOF
}
cleanup() {
	[ -z ${tmpdir+x} ] || rm -rf -- "$tmpdir"
}

## Core functions
step_validate_logs() {
	# Rotate the logfile, if necessary
	if [ -f "$logfile" ]; then
		log "Found old logfile. Rotating" 0
		mv "$logfile" "$logfile.old"
	fi
}
step_validate_deps() {
	# Ensure we have the proper dependencies
	log "Validating dependencies"
	for dep in $deps; do
		if ! validatedep "$dep"; then
			log "Could not find critical dependency \"$dep\"" 2
			return 1
		fi
	done
}
step_make_skeleton() {
	# Build Home folder skeleton
	log "Building skeleton folder layout"
	if ! mkdir Desktop Documents Downloads Games Music Pictures Projects Public ROMs System Templates Videos > /dev/null 2>&1; then
		log "Failed to build skeleton layout" 2
		return 1
	fi
	return 0
}
step_repo_clone() {
	# Clone the dotfiles
	log "Cloning repository into \"$tmpdir\""
	git clone --recursive --depth 50 --separate-git-dir="$gitdir" "$repo" "$tmpdir" >> "$logfile" 2>&1
	error="$?"
	if ! [ "$error" -eq "0" ]; then
		log "Failed cloning repository \"$repo\": git returned $error" 2
		log "See $logfile for details"
		log "Do you have the appropriate permissions? Does the remote host know your key?"
		return 1
	fi
}
step_repo_move() {
	# Move them to where they should be
	log "Moving cloned repo from \"$tmpdir\" into \"$bootstrapdir\""
	if ! rsync -rvl --exclude ".git" "$tmpdir/" "$bootstrapdir/" >> "$logfile"; then
		log "Failed to move from temp directory to bootstrap directory" 2
		return 1
	fi
}
step_dot_update() {
	# Finish syncing
	log "Updating submodules and performing basic configuration"
	{
	git --git-dir="$gitdir" --work-tree="$bootstrapdir" submodule update --init --recursive --remote --depth 50
	git --git-dir="$gitdir" --work-tree="$bootstrapdir" submodule foreach 'git checkout master && git pull'
	git --git-dir="$gitdir" --work-tree="$bootstrapdir" config status.showUntrackedFiles no >> "$logfile"
	} >> "$logfile" 2>&1
}

## Main
main() {
	# Set up some non-controlled variables
	name="$(basename "$0" .sh)" # Name of the program, used in logging
	deps="git rsync mktemp basename" # Critical dependencies
	tmpdir="$(mktemp -d "tmp.$USER.$name.XXXXXXXX" --tmpdir)"
	gitdir="$PWD/.dotfiles"

	# Parse out arguments
	while getopts ":d:r:lh\?" opt; do
		case $opt in
			d)
				if [ "$OPTARG" == "" ]; then
					log "Option -d requires an argument" 2
					exit 1
				fi
				bootstrapdir="$OPTARG"
				;;
			r)
				if [ "$OPTARG" == "" ]; then
					log "Option -r requires an argument" 2
					exit 1
				fi
				repo="$OPTARG"
				;;
			l)
				if [ "$OPTARG" == "" ]; then
					log "Option -l requires an argument" 2
					exit 1
				fi
				logfile="$OPTARG"
				;;
			\?|h)
				help
				;;
			*)
				log "Invalid option: \"$opt\"" 2
				exit 1
				;;
		esac
	done
	# Set up some user-controllable variables
	if [ -z ${bootstrapdir+x} ]; then
		bootstrapdir="$PWD"
		log "Using default bootstrap dir \"$bootstrapdir\"" 0
	fi
	if [ -z ${repo+x} ]; then
		repo='git@gitlab.com:rehashedsalt/home.git' 0
		log "Using default repository \"$repo\""
	fi
	if [ -z ${logfile+x} ]; then
		logfile="${PWD}/${name}.log" # Log file
	fi

	# Do the do
	trap cleanup EXIT
	step_validate_logs || exit $?
	step_validate_deps || exit $?
	step_make_skeleton || exit $?
	step_repo_clone || exit $?
	step_repo_move || exit $?
	step_dot_update || exit $?
	log "Dotfiles set up successfully"
	exit 0
}

main "$@"