#!/bin/bash

repos="$HOME/.homesick/repos"
# Include all helper functions. We will include the required command function later on.
homeshick=${HOMESHICK_DIR:-/usr/share/homeshick}
# On travis-ci exit_status for some reason errors out, ignore it
# shellcheck disable=SC1090
source "$homeshick/lib/exit_status.sh"
# shellcheck source=lib/fs.sh
source "$homeshick/lib/fs.sh"
# shellcheck source=lib/git.sh
source "$homeshick/lib/git.sh"
# shellcheck source=lib/log.sh
source "$homeshick/lib/log.sh"
# shellcheck source=lib/prompt.sh
source "$homeshick/lib/prompt.sh"

# lots of global variables in here, so just disable SC2034 for the entire file
# shellcheck disable=SC2034
true

exit_status=$EX_SUCCESS

type git &>/dev/null || err "$EX_SOFTWARE" "git not found in path"

if [[ ! -d $repos ]]; then
	mkdir -p "$repos"
fi

# used in pull.sh
# shellcheck disable=SC2034
T_START=$(date +%s)
if [[ -z $GIT_VERSION ]]; then
	read -r _ _ GIT_VERSION _ < <(command git --version)
	if [[ ! $GIT_VERSION =~ ([0-9]+)(\.[0-9]+){0,3} ]]; then
		err "$EX_SOFTWARE" "could not determine git version"
	fi
fi

TALK=true
SKIP=false
FORCE=false
BATCH=false
VERBOSE=false

# Retrieve all the flags preceeding a subcommand
while [[ $# -gt 0 ]]; do
	if [[ $1 =~ ^- ]]; then
		# Convert combined short options into multiples short options (e.g. `-qb' to `-q -b')
		if [[ $1 =~ ^-[a-z]{2,} ]]; then
			param=$1
			shift
			set -- "${param:0:2}" "-${param:2}" "$@"
			unset param
		fi
		case $1 in
			-h | --help)  cmd="help" ; shift; continue ;;
			-q | --quiet) TALK=false ; shift; continue ;;
			-s | --skip)  SKIP=true  ; shift; continue ;;
			-f | --force) FORCE=true ; shift; continue ;;
			-b | --batch) BATCH=true ; shift; continue ;;
			-v | --verbose) VERBOSE=true ; shift; continue ;;
			*)     err "$EX_USAGE" "Unknown option '$1'" ;;
		esac
	else
		break
	fi
done

[[ $# -gt 0 ]] || cmd="help"

# Get the subcommand
valid_commands=(cd clone generate list check updates refresh pull symlink link track help)
if [[ ! $cmd ]]; then
	# We actually want literal matching of the rhs here, $1 shouldn't be a regexp
	# shellcheck disable=SC2076
	if [[ " ${valid_commands[*]} " =~ " $1 " ]]; then
		cmd=$1
		shift
	fi
	if [[ ! $cmd ]]; then
		err "$EX_USAGE" "Unknown command '$1'"
	fi
fi

# Get the arguments for the subcommand, also parse flags if there are any left
while [[ $# -gt 0 ]]; do
	if [[ $1 =~ ^- ]]; then
		# Convert combined short options into multiples short options (e.g. `-qb' to `-q -b')
		if [[ $1 =~ ^-[a-z]{2,} ]]; then
			param=$1
			shift
			set -- "${param:0:2}" "-${param:2}" "$@"
			unset param
		fi
		case $1 in
			-h | --help)
				cmd="help"
				shift; continue ;;
			-q | --quiet)
				TALK=false
				shift; continue ;;
			-s | --skip)
				SKIP=true
				shift; continue ;;
			-f | --force)
				FORCE=true
				shift; continue ;;
			-b | --batch)
				BATCH=true
				shift; continue ;;
			-v | --verbose)
				VERBOSE=true
				shift; continue ;;
			*)     err "$EX_USAGE" "Unknown option '$1'" ;;
		esac
	fi

	case $cmd in
		cd | clone | generate | check | updates | pull | symlink | link)
			params+=("$1")
			shift; continue ;;
		refresh)
			[[ ! $threshhold ]] && threshhold=$(($1*86400)) || params+=("$1")
			shift; continue ;;
		track)
			[[ ! $castle ]] && castle=$1 || params+=("$1")
			shift; continue ;;
		list) err "$EX_USAGE" "The 'list' command does not take any arguments" ;;
		help)
			[[ ! $help_cmd ]] && help_cmd=$1
			shift; continue;;
		*) err "$EX_USAGE" "Unknown command '$1'" ;;
	esac
done

# If no additional arguments are given, run the subcommand for every castle
if [[ ${#params[@]} -eq 0 ]]; then
	case $cmd in
		check | updates | refresh | pull | symlink | link)
			while IFS= read -d $'\n' -r name ; do
				params+=("$name")
			done < <(list_castle_names) ;;
		# These commands require parameters, show the help message instead
		cd | clone | generate | track) help_cmd=$cmd; cmd="help"; exit_status=$EX_USAGE ;;
	esac
fi

# Default param for refresh is 7
[[ ! $threshhold ]] && threshhold=$((7*86400))

# Include the file that implements the invoked command
case $cmd in
	cd) ;;
	symlink)
		# shellcheck source=lib/commands/link.sh
		source "$homeshick/lib/commands/link.sh" ;;
	updates)
		# shellcheck source=lib/commands/check.sh
		source "$homeshick/lib/commands/check.sh" ;;
	*)
		# Don't know what will be included, so just disable the rule
		# shellcheck disable=SC1090
		source "$homeshick/lib/commands/$cmd.sh" ;;
esac

case $cmd in
	list)  list           ;;
	cd)    help cd        ;; # cd is implemented in the homeshick.{sh,csh} helper script.
	help)  help $help_cmd ;;
	*)
		for param in "${params[@]}"; do
			case $cmd in
				clone)
					clone "$param" ;;
				generate)
					generate "$param" ;;
				check|updates)
					(check "$param") ;;
				refresh)
					(refresh $threshhold "$param") ;;
				pull)
					(pull "$param") ;;
				symlink|link)
					symlink "$param" ;;
				track)
					track "$castle" "$param" ;;
			esac
			result=$?
			if [[ $result == "$EX_USAGE" ]]; then
				exit "$EX_USAGE"
			fi
			if [[ $exit_status == 0 && $result != 0 ]]; then
				exit_status=$result
			fi
		done
		case $cmd in
			clone)
				symlink_cloned_files "${params[@]}" ;;
			refresh)
				pull_outdated $threshhold "${params[@]}" ;;
			pull)
				symlink_new_files "${params[@]}" ;;
		esac
		result=$?
		if [[ $exit_status == 0 && $result != 0 ]]; then
			exit_status=$result
		fi
		;;
esac

exit $exit_status
