# Generic bash helpers

# Generic helpers for terminal sessions and bash scripts. Should stay
# fast to load, so it could be safely included in .profile or .bashrc.
#
# Requires: bash v5+
# License: GNU Affero GPL v3.0
# https://github.com/magicoli/build-tools.git

# TODO: rename properly and adjust all scripts consuming it from other projects.

clean_path() {
	local path
	local newpath=
	local keepifs=$IFS

	IFS=:
	for path in $PATH; do
		path=${path%/}
		[ -d "$path" ] || continue
		case ":$newpath:" in
		*":$path:"*) continue ;;
		esac
		newpath="${newpath:+${newpath}:}${path}"
	done
	IFS=$keepifs
	PATH=$newpath
}

add_path() {
	local position
	local path
	local add

	for path in $(echo "$@" | tr ':' ' '); do
		case $path in
		-b | --before)
			position=before
			continue
			;;
		-a | --after)
			position=after
			continue
			;;
		esac
		echo "$path" | grep -q "^-" && continue
		[ -f "$path" ] && path=$(cd $(dirname "$path") && pwd)
		path=$(cd "$path" 2>/dev/null && pwd)
		[ -z "$path" ] && continue
		[ -d "$path" ] && add="${add:+${add}:}$path"
	done

	case $position in
	before)
		PATH=${add:+${add}:}"$PATH"
		;;
	*)
		PATH="$PATH"${add:+:${add}}
		;;
	esac

	# clean_path
}

prepend_path() {
	add_path --before "$@"
}

append_path() {
	add_path --after "$@"
}

# Utility functions for true/false checking
is_true() {
	local lower=${*,,}

	case "$lower" in
	yes | y | on | true | 1) return 0 ;;
	*) return 1 ;;
	esac
}

is_false() {
	local lower=${*,,}

	case "$lower" in
	no | n | off | false | 0) return 0 ;;
	# "") return 0 ;;  # Empty is not false, it's null
	*) return 1 ;; # Unknown is false
	esac
}

is_numeric() {
	echo "$@" | grep -v "\..*\." | grep -Eq "^[0-9\.]*$"
	return $?
}

is_integer() {
	echo "$@" | grep -Eq "^[0-9]+$"
	return $?
}

log() {
	[ -z "$*" ] && return
	local append err

	err=$(echo "$1" | grep -E "^[0-9]+$" || true)
	[ -z "$err" ] || shift

	case "$err" in
	0) COLOR=${GREEN} ;;
	"") COLOR=${YELLOW} ;;
	*)
		COLOR="$RED"
		append=" ($err)"
		;;
	esac

	[ "${1:-}" = "-n" ] && n="-n" && shift || n=
	[ -n "$*" ] || return
	(
		printf "${COLOR}%s:${STD} %s" "${LOG_PREFIX:-$PGM}" "$*${append:-}"
		is_true "${LOG_TRACE:-no}" && printf " (%s)" "$(ansi_color underline)$(caller | sed "s:$BASE_DIR/*::;")${STD}"
		printf "\n"
	) >&2
}

# One key answers on a terminal, Enter takes the default; a line is read when the input is not a terminal
yesno() {
	local default=n choice="y/N" answer message

	[ "$1" = "y" ] && default=y && choice="Y/n" && shift
	[ "$1" = "-y" ] && default=y && choice="Y/n" && shift
	[ "$@" ] && message="$@" || message="Answer"
	message="$message ($choice) "
	if [ -t 0 ]; then
		read -r -n 1 -p "$message" answer || answer=
		[ -z "$answer" ] || printf '\n' >&2
	else
		read -r -p "$message" answer || answer=
	fi
	[ "$answer" = "" ] && answer=$default
	answer=$(echo "$answer" | tr "[:upper:]" "[:lower:]")
	[ "$answer" = "y" ] && return 0
	[ "$answer" = "yes" ] && return 0
	return 1
}

readvar() {
	local var varname

	for var in $@; do
		varname=$(echo $var | sed "s/\([a-z]\)\([A-Z]\)/\\1 \\2/g")
		if [ "$AUTOMATIC" = "yes" ]; then
			echo "$varname: ${!var}"
		else
			read -e -p "$varname: " -i "${!var}" $var
		fi
	done
}
