#!/bin/bash
# shebang for syntax highlighting purposes

# Colors
_NON="\[\033[0m\]"
_BLD="\[\033[1m\]" # YEP BALD
_BLK="\[\033[30m\]"
_RED="\[\033[31m\]"
_GRN="\[\033[32m\]"
_YLW="\[\033[33m\]"
_BLU="\[\033[34m\]"
_PRP="\[\033[35m\]"
_CYN="\[\033[36m\]"
_WHT="\[\033[37m\]"

__debug_trap() {
	# Set necessary pre-command variables (PROMPT_COMMAND is a
	# command so its excluded here)
	if [[ "$BASH_COMMAND" != "$PROMPT_COMMAND"
		&& "$LAST_BASH_COMMAND" == "$PROMPT_COMMAND" ]]; then
		INC_TIME=1
		LAST_RT="$EPOCHREALTIME" # This should be the last thing done in this function
	fi
	LAST_BASH_COMMAND="$BASH_COMMAND"
}

trap '__debug_trap' DEBUG

__get_cmd_time() {
	# Set hours minutes seconds and remove preceding zeros
	local YEAR
	local DAYS
	local HOUR
	local MINS
	local SECS
	((YEAR=10#$(($(TZ=UTC printf '%(%Y)T' "$CMD_TIME")))-1970))
	((DAYS=10#$(TZ=UTC printf '%(%j)T' "$CMD_TIME")))
	((HOUR=10#$(TZ=UTC printf '%(%H)T' "$CMD_TIME")))
	((MINS=10#$(TZ=UTC printf '%(%M)T' "$CMD_TIME")))
	((SECS=10#$(TZ=UTC printf '%(%S)T' "$CMD_TIME")))

	# Choose whether or not to print hours minutes and seconds
	[[ $CMD_TIME -ge 31536000 ]] && printf '%sy ' "${YEAR}"
	[[ $CMD_TIME -ge 86400    ]] && printf '%sd ' "${DAYS}"
	[[ $CMD_TIME -ge 3600     ]] && printf '%sh ' "${HOUR}"
	[[ $CMD_TIME -ge 60       ]] && printf '%sm ' "${MINS}"
	[[ $CMD_TIME -ge 1        ]] && printf '%ss ' "${SECS}"
	# If you want to have a limit uncomment the next line and replace somenum with
	# the minimum microseconds
#	[[ $CMD_US   -ge somenum  ]] &&
	                                printf '%sμs' "${CMD_US:-0}"
}

__sig() {
	# Giant switch case for getting the name of the signal (`kill -l`)
	local ITR=0
	local RET
	for RET in "$@"; do
		if [[ $ITR != 0 ]]; then
			printf '%s|%s' "$_WHT" "$_RED"
		fi
		((ITR++))
		case $RET in
			126): "ACCES"  ;;
			127): "NOENT"  ;;
			129): "HUP"    ;;
			130): "INT"    ;;
			131): "QUIT"   ;;
			132): "ILL"    ;;
			133): "TRAP"   ;;
			134): "ABRT"   ;;
			135): "BUS"    ;;
			136): "FPE"    ;;
			137): "KILL"   ;;
			138): "USR"1   ;;
			139): "SEGV"   ;;
			140): "USR"2   ;;
			141): "PIPE"   ;;
			142): "ALRM"   ;;
			143): "TERM"   ;;
			144): "STKFLT" ;;
			145): "CHLD"   ;;
			146): "CONT"   ;;
			147): "STOP"   ;;
			148): "TSTP"   ;;
			149): "TTIN"   ;;
			150): "TTOU"   ;;
			151): "URG"    ;;
			152): "XCPU"   ;;
			153): "XFSZ"   ;;
			154): "VTALRM" ;;
			155): "PROF"   ;;
			156): "WINCH"  ;;
			157): "IO"     ;;
			158): "PWR"    ;;
			159): "SYS"    ;;
			16[3-9]|1[7-8][0-9]|19[0-2]): "RT$((RET-128))" ;; # Savagery
			*):   "$RET"   ;; # Print exit code if not in list
		esac
		printf '%s' "$_"
	done
}

__ssh() {
	local CON=($SSH_CONNECTION)
	local SRV_IP="${CON[2]}"
	[[ -z "$SRV_IP" ]] && return
	local SRV_PORT="${CON[3]}"
	# 4 chars from startand 4 chars from end
	local SRV_IP_CUT="${_CYN}${SRV_IP}"
	[[ ${#SRV_IP} -gt 8 ]] && local SRV_IP_CUT="${_CYN}${SRV_IP:0:4}${_WHT}*${_CYN}${SRV_IP: -4}"

	printf '%s' "${_GRN}${_BLU}[${SRV_IP_CUT}${_PRP}${_BLD}:${_NON}${_CYN}${SRV_PORT}${_BLU}]${_NON}"
}

__prompt() {
	# Get exit code (must be first)
	local PLC=("${PIPESTATUS[@]}")

	# Reset time when prompt was first displayed after command
	# this contributes to the ~40 microsecond difference in $CMD_US and the actual time it took
	if [[ "$INC_TIME" != 0 ]]; then 
		PROMPT_RT="$EPOCHREALTIME"
		INC_TIME=0
	fi

	# *_RT may not be set
	LAST_RT="${LAST_RT:-$EPOCHREALTIME}"
	PROMPT_RT="${PROMPT_RT:-$EPOCHREALTIME}"

	# Get relative times

	# Remove decimal point, simulating multiplying by 1 million
	PROMPT_RT1M="${PROMPT_RT/.}"
	PROMPT_RT1M="${PROMPT_RT1M/,}"
	LAST_RT1M="${LAST_RT/.}"
	LAST_RT1M="${LAST_RT1M/,}"

	((CMD_US=PROMPT_RT1M-LAST_RT1M))

	CMD_TIME=0

	# Divide by 1 million to get a more accurate difference
	((CMD_TIME=CMD_US/1000000))

	[[ ${#CMD_US} -lt 6 ]] || CMD_US="${CMD_US: -6}"
	((CMD_US=10#$CMD_US))

	# Set prompt sections

	local SIG
	local COL
	local UHD
	local TIME
	local IND

	# Text

	# ssh detection and indicator
	[[ "$SSH_CONNECTION" ]] && local SSH="$(__ssh) "

	# [INT], [4], etc.
	local RET
	for RET in "${PLC[@]}"; do
		if [[ $RET -gt 0 ]]; then
			SIG="$(printf '%s[%s%s%s] ' "$_BLU" "$_RED" "$(__sig "${PLC[@]}")" "$_BLU")"
			break
		fi
	done

	# [user@homeserver:~]
	COL="$([[ $UID == 0 ]] && printf '%s' "$_RED" || printf '%s' "$_YLW")"
	UHD="${_BLD}${_BLU}[${COL}\u${_PRP}@${_CYN}\h${_PRP}:${_GRN}\w${_BLU}]"

	# 2y 351d 12m 43s 382969μs
	TIME="${_YLW}$(__get_cmd_time)"

	# Random colored $ or #
	_RAND256="\[\033[38;2;$((RANDOM%256));$((RANDOM%256));$((RANDOM%256))m\]"
	IND="${_RAND256}\\$"

	# Set the prompt
	PS1="${_NON}${SSH}${SIG}${UHD} ${TIME} ${IND} ${_NON}"
}
	
PROMPT_COMMAND=__prompt
