#!/bin/bash
#########################################################
# 							#
# This is BashStyle-NG  				#
#							#
# Licensed under GNU GENERAL PUBLIC LICENSE v3    	#
#							#
# Copyright 2007 - 2017 Christopher Bratusek		#
#							#
#########################################################

. gettext.sh
TEXTDOMAIN="bashstyle-rc"

export BSNG_PREFIX=@PREFIX@
export BSNG_DATADIR=@DATADIR@
export BSNG_RCDIR=${BSNG_DATADIR}/bashstyle-ng/rc
export BSNG_VERSION=@VERSION@
export BSNG_YEAR="2007 - 2017"
export BSNG_BASHVER=${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}
export BSNG_LOGFILE=${HOME}/.bashstyle.log
INI_VERSION=31

source ${BSNG_RCDIR}/internal/misc
source ${BSNG_RCDIR}/internal/logging

dbg_log rm -f "${BSNG_LOGFILE}"
dbg_log touch "${BSNG_LOGFILE}"

dbg_msg $"BashStyle-NG Starting"
dbg_msg $"BashStyle-NG Bash Major Version:" "${BASH_VERSINFO[0]}"
dbg_msg $"BashStyle-NG Bash Minor Version:" "${BASH_VERSINFO[1]}"
dbg_msg $"BashStyle-NG Bash Patch Level:" "${BASH_VERSINFO[2]}"
dbg_msg $"BashStyle-NG Version:" "${BSNG_VERSION}"
dbg_msg $"BashStyle-NG Prefix:" "${BSNG_PREFIX}"
dbg_msg $"BashStyle-NG Logfile:" "${BSNG_LOGFILE}"
dbg_msg $"BashStyle-NG Ini Version:" "${INI_VERSION}"

if [[ ! -f ${HOME}/.bs-ng.ini ]]; then
	dbg_msg $"No user ini file (" "${HOME}"/.bs-ng.ini $") found"
	if [[ -f /etc/bs-ng_vendor.ini && $(ven_get ini_version) == "${INI_VERSION}" ]]; then
		dbg_msg $"found an up-to-date vendor ini (/etc/bs-ng_vendor.ini), copying as user ini"
		cp /etc/bs-ng_vendor.ini "${HOME}"/.bs-ng.ini
	else
		dbg_msg $"no (up-to-date) vendor ini found"
		dbg_msg $"using factory ini (" "${BSNG_DATADIR}"/bashstyle-ng/bs-ng.ini $"), copying as user ini"
		cp "${BSNG_DATADIR}"/bashstyle-ng/bs-ng.ini "${HOME}"/.bs-ng.ini
	fi
else
	if [[ $(ini_get ini_version) != "${INI_VERSION}" ]]; then
		dbg_msg $"user configuration is not up-to-date"
		dbg_msg $"expected version" "${INI_VERSION}" $"but got" "$(ini_get ini_version)"
		dbg_msg $"running config update helper"
		dbg_log bashstyle --update
	fi
fi

dbg_log shopt -s checkwinsize

if [[ $(ini_get path) != "" ]]; then
	dbg_msg $"BashStyle-NG Setting:" PATH "${PATH}"
	PATH="$(ini_get path)"
fi

[[ ${PATH} != *games* && -d /usr/games/ ]] && \
	export PATH="${PATH}:/usr/games/:/usr/local/games/"

[[ ${PATH} != *bashstyle-ng/rc* ]] && \
	export PATH="@DATADIR@/bashstyle-ng/rc/functions/:${PATH}"

[[ $(ini_get path_wd) == True ]] && export PATH="${PATH}:."

[[ $(ini_get enable_colors) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/color-rc

[[ $(ini_get use_lscolors) == True && $(ini_get enable_colors) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/ls-rc

[[ $(ini_get use_readlinecfg) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/readline-rc

[[ $(ini_get use_vimcfg) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/vim-rc

[[ $(ini_get use_nanocfg) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/nano-rc

[[ $(ini_get use_gitcfg) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/git-rc

[[ $(ini_get use_keybindingscfg) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/keybindings-rc

[[ $(ini_get less_termcap_color) == True ]] && \
	dbg_log source ${BSNG_RCDIR}/settings/man-rc

dbg_msg $"BashStyle-NG Setting:"  Shopts
dbg_log source ${BSNG_RCDIR}/settings/shopt-rc

dbg_log source ${BSNG_RCDIR}/settings/alias-rc

if [[ -e ${HOME}/.bashstyle.custom ]]; then
	dbg_msg $"BashStyle-NG Loading:" $"Custom Settings"
	dbg_log source "${HOME}"/.bashstyle.custom
fi

if [[ $(ini_get use_bashstyle) == True ]]; then

	dbg_msg $"BashStyle-NG Loading:" BashStyle-NG
	dbg_log source ${BSNG_RCDIR}/styles/null-rc

	if [[ ${BSNG_BASHVER} -ge 44 && $(ini_get ps0) != "" ]]; then
		dbg_msg $"BashStyle-NG Setting:" PS0 "$(ini_get ps0)"
		PS0="${color_ps0} $(ini_get ps0)${color_font} "
	fi

	dbg_msg $"BashStyle-NG Setting:" PS2 "$(ini_get ps2)"
	PS2="${color_ps2} $(ini_get ps2)${color_font} "

	dbg_msg $"BashStyle-NG Setting:" PS3 "$(ini_get ps3)"
	PS3="${color_ps3} $(ini_get ps3)${color_font} "

	dbg_msg $"BashStyle-NG Setting:" PS4 "$(ini_get ps4)"
	PS4="${color_ps4} $(ini_get ps4)${color_font} "

	if [[ $(ini_get random_style) == True ]]; then
		dbg_msg $"BashStyle-NG Setting:" $"Random Prompt"

		number=$(random -r 11)
		case ${number} in
			0 ) pstyle=separator ;;
			1 ) pstyle=vector ;;
			2 ) pstyle=clock ;;
			3 ) pstyle=equinox ;;
			4 ) pstyle=elite ;;
			5 ) pstyle=poweruser ;;
			6 ) pstyle=dirks ;;
			7 ) pstyle=dot_prompt ;;
			8 ) pstyle=sepa_ng ;;
			9 ) pstyle=quirk ;;
			10 ) pstyle=sputnik ;;
			11 ) pstyle=ayoli ;;
		esac

		dbg_msg $"BashStyle-NG Setting:" ${pstyle} $"randomly chosen"
	else
		pstyle=$(ini_get prompt_style)
		if [[ ${pstyle} == clock-ad ]]; then
			dbg_msg $"Clock Advanced prompt style is deprecated, changing to Equinox"
			pstyle="equinox"
			ini_set prompt_style equinox
		fi
	fi

	use_custom_prompt=$(ini_get use_custom_prompt)

	if [[ ${use_custom_prompt} == True ]]; then
		dbg_msg $"BashStyle-NG Setting:" $"Custom" Prompt
		dbg_log source ${BSNG_RCDIR}/styles/custom-rc
	elif [[ -e ${BSNG_RCDIR}/styles/${pstyle}-rc ]]; then
		dbg_msg $"BashStyle-NG Setting:" ${pstyle} Prompt
		dbg_log source ${BSNG_RCDIR}/styles/${pstyle}-rc
	else
		dbg_msg $"BashStyle-NG Setting:" $"Fallback" Prompt
		dbg_log export PS1="\u@\h\w: "
	fi

fi

dbg_log source ${BSNG_RCDIR}/settings/options-rc

# by Richard Hansen https://stackoverflow.com/a/7287873

log () { printf '%s\n' "$*"; }
error () { log "ERROR: $*" >&2; }
fatal () { error "$@"; exit 1; }

trap_add () {
    trap_add_cmd=$1; shift || fatal "${FUNCNAME[0]} usage error"
    for trap_add_name in "$@"; do
        trap -- "$(
            extract_trap_cmd() { printf '%s\n' "$3"; }
            eval "extract_trap_cmd $(trap -p "${trap_add_name}")"
            printf '%s\n' "${trap_add_cmd}"
        )" "${trap_add_name}" \
            || fatal "unable to add to trap ${trap_add_name}"
    done
}

declare -f -t trap_add

# do trapping stuff

if [[ $(ini_get colorshell) && $(ini_get enable_colors) == True ]]; then

	_colorshell () {
		if [[ ${OLDPS1} == "" ]]; then
			[[ ${BSNG_BASHVER} -ge 44 ]] && OLDPS0="${PS0}"
			OLDPS1="${PS1}"
			OLDPS2="${PS2}"
			OLDPS3="${PS3}"
			OLDPS4="${PS4}"
		fi

		# exclude black (0) on dark terminal
		# exclude white (7) on bright terminal
		if [[ $(ini_get dark_terminal) == True ]]; then
			randomcolor=$(random -r 1 7)
		else	randomcolor=$(random -r 0 6)
		fi

		cmd_text_colour='\[`tput setaf ${randomcolor}`\]'

		shopt -s promptvars

		[[ ${BSNG_BASHVER} -ge 44 ]] && PS0="${OLDPS0}${cmd_text_colour}"
		PS1="${OLDPS1}${cmd_text_colour}"
		PS2="${OLDPS2}${cmd_text_colour}"
		PS3="${OLDPS3}${cmd_text_colour}"
		PS4="${OLDPS4}${cmd_text_colour}"

	}
	dbg_msg $"Add colorshell to DEBUG trap"
	trap_add '_colorshell' DEBUG

	if [[ $(ini_get colorshell_reset) == True ]]; then

		_colorshell_reset () {
			echo -ne "\e[0m"
		}

		dbg_msg $"Add colorshell-reset to DEBUG trap"
		trap_add '_colorshell_reset' DEBUG
	fi
fi

if [[ $(ini_get history_sync) == True ]]; then

	_erasehistorydups () {
		gawk '/^#/{if (x)print x;x="";}{x=(!x)?$0:x"HISTDILIMITER"$0;}END{print x;}' "${HISTFILE}" | \
			tac | gawk -F'HISTDILIMITER' '!x[$2]++' | \
			tac | sed -e 's/HISTDILIMITER/\n/g' > "${HISTFILE}".tmp
	}

	_ignorehistorydups () {
		gawk '/^#/{if (x)print x;x="";}{x=(!x)?$0:x"HISTDILIMITER"$0;}END{print x;}' "${HISTFILE}" | \
			gawk -F'HISTDILIMITER' '!x[$2]++' | \
			sed -e 's/HISTDILIMITER/\n/g' > "${HISTFILE}".tmp
	}

	_ignorehistoryspc () {
		gawk '/^#/{if (x)print x;x="";}{x=(!x)?$0:x"HISTDILIMITER"$0;}END{print x;}' "${HISTFILE}" | \
			sed -e '/HISTDILIMITER /d' > "${HISTFILE}".tmp
	}

	_ignorehistoryboth () {
		_ignorehistorydups
		_ignorehistoryspc
	}

	_synchistory () {
		builtin history -a
		builtin history -c

		case ${HISTCONTROL} in
			erasedups )	_erasehistorydups ;;
			ignoredups)	_ignorehistorydups ;;
			ignorespace)	_ignorehistorspc ;;
			ignoreboth)	_ignorehistoryboth ;;
		esac

		if [[ -f ${HISTFILE}.tmp ]]; then
			mv "${HISTFILE}".tmp "${HISTFILE}" &>/dev/null && \
			builtin history -r
		fi
	}

fi

# remember last exit status and command

if [[ ${TERM} != *xterm* ]]; then
	return_good="+"
	return_bad="-"
	return_other="/"
else
	if [[ $(ini_get return_good) != "" ]]; then
		return_good="$(ini_get return_good)"
	else	return_good="✔"
	fi

	if [[ $(ini_get return_bad) != "" ]]; then
		return_bad="$(ini_get return_bad)"
	else	return_bad="✘"
	fi

	if [[ $(ini_get return_other) != "" ]]; then
		return_other="$(ini_get return_other)"
	else	return_other="⊘"
	fi
fi

remember_command_debug () {
	local _lastexit=$?
	[[ "${BSNG_TRAP_RECORD}" != True ]] && return
	[ -n "$COMP_LINE" ] && return
	[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return
	[[ "$BASH_COMMAND" == trap\ * ]] && return
	[[ "$BASH_COMMAND" == *lastcommand* ]] && return
	[[ "$BASH_COMMAND" == *lastexit* ]] && return
	local X_COMMAND=${BASH_COMMAND//$'\n'/ }
	X_COMMAND=${X_COMMAND//\\n/ }
	lastcommand=${BASH_COMMAND}
	lastcommandprintable=${X_COMMAND:0:21}
	if [ ${#lastcommandprintable} -gt 21 ]; then
		lastcommandprintable=${lastcommandprintable:0:20}'>'
	else
		lastcommandprintable="$(printf '%-21s' "$lastcommandprintable")"
	fi
	lastexit=${_lastexit}
}

remember_command_err () {
	local _lastexit=$?
	[[ "${BSNG_TRAP_RECORD}" != True ]] && return
	lastexit=${_lastexit}
}


if [[ $(ini_get user_birthday) == $(date +%m-%d) ]]; then
	cat ${BSNG_RCDIR}/internal/birthday
elif [[ $(ini_get welcome_message) != "" ]]; then
	dbg_msg $"BashStyle-NG Setting:" $"Welcome Message"
	dbg_log $(ini_get welcome_message)
fi

lscd() {
	OLD_PWD=${PWD}
	clear

	if [[ -f "${1}" ]]; then
		builtin cd "${1%/*}" &>/dev/null
	elif [[ -d "${1}" ]]; then
		builtin cd "${1}" &>/dev/null
	elif [[ "${1}" == -*   ]]; then
		builtin cd "${*}" &>/dev/null
	elif [[ ! "${1}" ]]; then
		builtin cd
	elif [[ $(ini_get customcd_mkdir) == True ]]; then
		mkdir -p "${1}"
		builtin cd "${1}" &>/dev/null
	fi

	if [[ ${OLD_PWD} != "${PWD}" ]]; then
		echo -e "\n${ccolor_banner}content:\n"
		if [[ $(systemkit countvisibleitems) -gt 0 ]]; then
			ls ${LSCD_OPTS}
		else	echo -e "${ccolor_empty}-- empty --\n"
		fi
	fi

	echo "${PWD}" > "${HOME}"/.lastpwd
}

treecd () {
	OLD_PWD=${PWD}
	clear

	if [[ -f "${1}" ]]; then
		builtin cd "${1%/*}" &>/dev/null
	elif [[ -d "${1}" ]]; then
		builtin cd "${1}" &>/dev/null
	elif [[ "${1}" == -*   ]]; then
		builtin cd "${*}" &>/dev/null
	elif [[ ! "${1}" ]]; then
		builtin cd
	elif [[ $(ini_get customcd_mkdir) == True ]]; then
		mkdir -p "${1}"
		builtin cd "${1}" &>/dev/null
	fi

	if [[ ${OLD_PWD} != "${PWD}" ]]; then
		echo -e "\n${ccolor_banner}content:\n"
		if [[ $(systemkit countvisibleitems) -gt 0 ]]; then
			tree -L ${TREECD_OPTS}
		else	echo -e "${ccolor_empty}-- empty --\n"
		fi
	fi

	echo "${PWD}" > "${HOME}"/.lastpwd
}

if [[ $(ini_get use_treecd) == True ]]; then
	if which tree; then
		dbg_log alias cd=treecd
		dbg_log export TREECD_OPTS="$(ini_get treecd_opts)"
		[[ $(ini_get enable_colors) != True ]] && dbg_log export TREECD_OPTS="${TREECD_OPTS} -n"
	else	dbg_msg $"tree not found, not using treecd as cd replacement"
	fi
fi

if [[ $(ini_get use_lscd) == True ]]; then
	dbg_log alias cd=lscd
	dbg_log export LSCD_OPTS="$(ini_get lscd_opts)"
	[[ $(ini_get enable_colors) != True ]] && dbg_log export LSCD_OPTS="${LSCD_OPTS} --color=no"
fi

reload_bash () {
	#xk2c from commandlinefu.com
	builtin unalias -a
	builtin unset -f "$(builtin compgen -A function)"
	[[ -f /etc/bash_completion ]] && source /etc/bash_completion
	source "${HOME}"/.bashrc
}

unset style

if [[ $(ini_get history_sync) == True ]]; then
	dbg_msg $"Add history syncronization to DEBUG trap"
	trap_add '_synchistory' DEBUG
fi

dbg_msg $"Add remember command to DEBUG and ERR trap"
trap_add 'remember_command_debug' DEBUG
trap_add 'remember_command_err' ERR

lastcommand=""
lastcommandprintable="                     "
lastexit=0

dbg_finalize

export BSNG_TRAP_RECORD=True
