# -*- shell-script -*-

################################################################################

bashrun_debug_action=0

function §defined? {
    [[ "${!1-X}" == "${!1-Y}" ]]
}

function §set? {
    (set -o | grep "$1" | grep on) &>/dev/null
}

function §check_deps {

    local deps="sed grep tput stty kill sleep ldd uname"
    local missing dep

    for dep in $deps; do
	if ! type -t "$dep" &> /dev/null; then
	    [[ "$missing" =~ $dep ]] || missing+="$dep "        
	fi
    done

    if [[ -n "$missing" ]]; then
	source "$bashrun_site/message"
	§message "Error" \
	    "External dependencies not met:

             $missing

             Please install these programs and/or put them on your PATH."
	exit 1
    fi
}

function §cygwin? {
    [[ "$(uname)" =~ CYGWIN ]]
}

function §winch {
    if [[ "$(stty -a)" =~ rows\ ([0-9]+)\;\ columns\ ([0-9]+) ]]; then
	LINES="${BASH_REMATCH[1]}"
	COLUMNS="${BASH_REMATCH[2]}"
    fi
}

function §function.defined? {
    [[ "$(type -t $1 2> /dev/null)" == "function" ]]
}

function §function.exported? () {
    declare -pfx | grep "declare -fx $1" &>/dev/null
}	

function §function.code {
    printf '%s\n' "$(type $1 | sed '1 d')"
}

function §function.clone {

    local function="$1"
    local newname="$2"

    if $(type -t "$function" &> /dev/null); then
	local code="$(§function.code "$function")"
	code="${code/$function \(\)/$newname ()}"
	eval "$code"
    else
	printf '%s\n' "§function.clone: error: no such function: $function"
    fi
}

function §syntax? {
    local file="$1"
    local errorfile="$bashrun_cache_home/syntax-errors"
    local errors=""

    bash -n "$1" &> "$errorfile"
    errors="$(<$errorfile)"
    [[ -z "$errors" ]] && /bin/rm "$errorfile"

    [[ -z "$errors" ]]
}

function §quote { 
    declare -i times=1 i=0
    local varname=""

    if [[ "$1" =~ [0-9]+ ]]; then
	times=$1
	shift
    fi
    for varname; do
	for (( i=0; i<$times; i++ )); do
	    eval "printf -v $varname '%q' \"\$$varname\""
	done
    done
}

function §interpolate {
    local str="$1"
    local var=""
    local val=""
    local word=""
    local col=""

    local r="\033[0;31m" # red
    local g="\033[0;32m" # green 
    local n="\033[0m"    # none

    while [[ "$str" =~ \$([A-Za-z0-9_]+) ]]; do
	var="${BASH_REMATCH[1]}"
	val="${!var}"
	val="${val//\$/__DoLlArSiGn__}"

	if (( $# > 1 )); then
	    for word in $val; do break; done
	    if type "$word" &>/dev/null; then
		col="$g"
	    else
		col="$r"
	    fi
	    val="$col$val$n"
	fi

	str="${str/\$$var/$val}"
    done
    str="${str//__DoLlArSiGn__/\$}"
    printf '%s\n' "$str"
}

function §replace {

    # §replace 'foo %b bar \%baz' %b quux
    # -> "foo quux bar %baz"

    local string="$1"
    local prefix="${2:0:1}"
    local pattern="${2:1}"
    local replacement="$3"

    local result="" char="" prev="" next=""
    declare -i i=0 k=0 slen=${#string} plen=${#pattern}

    for ((i=0; i < slen; i++)); do
	char="${string:$i:1}"
	k=i+1; next="${string:$k:1}"
	if [[ "$char" == "$prefix" ]]; then
	    if [[ "$prev" != '\' ]]; then
		k=i+1
		if [[ "${string:$k:$plen}" == "$pattern" ]]; then
		    result+="$replacement"
		    i+=plen
		    prev=""
		    continue
		fi
	    fi
	fi
	
	if ! [[ "$char" == '\' && "$next" == "$prefix" ]]; then
	    result+="$char"	    
	fi
	prev="$char"
    done
    printf '%s' "$result"
}

function §debug {

    (( bashrun_debug )) || return 1
    
    # color

    local w="\033[1;37m" # white
    local r="\033[1;31m" # red
    local g="\033[1;32m" # green 
    local b="\033[1;34m" # blue
    local c="\033[1;36m" # cyan
    local m="\033[1;35m" # magenta
    local y="\033[1;33m" # yellow
    local n="\033[0m"    # none
    local d="$b"         # default
    local v="$w"         # variable

    local col=""

    # print function name
    
    local _func="${FUNCNAME[1]}"
    _func="${_func//}"
    _func="${_func/§/}"
    
    local _from="${FUNCNAME[2]}"
    _from="${_from//}"
    _from="${_from:-shell}"

    case $1 in	
	fail)
	    col="$r"
	    shift
	    ;;
	warn)
	    col="$y"
	    shift
	    ;;
	info)
	    col="$g"
	    shift
	    ;;
	emph)
	    col="$c"
	    shift
	    ;;
	*)
	    col="$g"
	    ;;
    esac
    
    if (( bashrun_debug_action )); then
	printf '%b' "$col$_from$n $d" >&2
    else
	printf '%b' "$col$_func$n $d" >&2
    fi

    local str=''
    local requested=0

    for str; do
	
	if [[ "${str:0:1}" == "-" && "$str" != "->" ]]; then # color option
	    col="${str:1:1}"
	    printf '%b' "${!col}" >&2
	    requested=1
	else
	    ! (( requested )) && printf '%b' "$d" >&2 
	    printf '%b' "$str " >&2
	    requested=0
	fi
    done
    printf '%b\n' "$n" >&2
}

function §separator {

    (( bashrun_debug )) || return 1

    local y="\033[1;33m" # yellow
    local b="\033[1;34m" # blue
    local n="\033[0m"    # none

    local prefix="--"
    case "$1" in
	begin)
	    prefix=">>"
	    shift
	    ;;
	end)
	    prefix="<<"
	    shift
	    ;;
    esac

    local title="$1"
    local width="${2:-$COLUMNS}"
    local line=""
    
    printf '%b' "$b" >&2
    if [[ -n "$title" ]]; then
	(( width = width - ${#title} - 4 )) 
	printf '%b' "$prefix $y$title$b " >&2
    fi

    printf -v line '%*s' "$width" 
    printf "%s" "${line// /-}" >&2
    printf '%b' "$n" >&2
}

function §prepare_logfile {

    # set to /dev/null if empty
    if [[ -z "$bashrun_logfile" ]]; then 
	bashrun_logfile="/dev/null"
    fi
 
    # create logfile unless it exists
    if [[ ! -e "$bashrun_logfile" ]]; then
	§debug "creating logfile $bashrun_logfile"
	touch "$bashrun_logfile"
    fi

    # revert to /dev/null unless writable
    if [[ ! -w "$bashrun_logfile" ]]; then
	§debug "logfile $bashrun_logfile is not writeable, using /dev/null"
	bashrun_logfile="/dev/null"
    fi
}

function §ks2kn {
    local keyseq="$1"

    if §keynames.seek "$keyseq"; then
	printf '%s' "$(§keyname.get_name)"
	return 0
    fi

    local enter="Ret"
    local keyname="$keyseq"

    keyname="${keyname/\\e/M-}"
    keyname="${keyname/\\C-/C-}"
    keyname="${keyname/\\M-/M-}"
    keyname="${keyname/\\C-/C-}"
    keyname="${keyname/\\\?/?}"

    keyname="${keyname/C-m/$enter}"
    if [[ "$keyname" =~ [a-zA-z]$enter ]]; then
	keyname="${keyname/$enter/-$enter}"
    fi
    printf '%s' "$keyname"
}

function §tilde_path {
    # replace $HOME with a tilde for printing
    local path="$1"
    path="${path/$HOME/~}"
    printf '%s' "$path"
}
