# -*- shell-script -*-

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

bashrun_command=''
bashrun_command_line=''
bashrun_command_word=''
bashrun_command_hold=''
bashrun_command_page=''
bashrun_command_su=''
bashrun_original_command=''

function §command.unquote {

    local command="$bashrun_command"

    # unquote quoted &;|
    command=${command//\\&/&}
    command=${command//\\|/|}
    command=${command//\\;/;}
    command=${command//&&/ && }
    command=${command//||/ || }

    bashrun_command="$command"
}

function §command.get_line {
    # updates bashrun_command_line to contain the complete and
    # verbatim line entered by the user.
    
    local command_line=''
    local histtimeformat=$HISTTIMEFORMAT
    unset HISTTIMEFORMAT

    [[ $(history 1) =~ \ +[0-9]+\ +(.+) ]]
    bashrun_command_line=${BASH_REMATCH[1]}
    
    if [[ -n "$histtimeformat" ]]; then
	HISTTIMEFORMAT=$histtimeformat
    fi
    printf '%s' "$bashrun_command_line"
}

function §command.get_word {

    # updates bashrun_command_word to contain the first word of the
    # current command that does not contain a '='. The current command
    # may be the command that was previously wrapped in a hold, page
    # or su invocation.

    local word=""
    local command="$bashrun_command"

    [[ "$bashrun_command_hold" ]] && command="$bashrun_command_hold"
    [[ "$bashrun_command_page" ]] && command="$bashrun_command_page"
    [[ "$bashrun_command_su" ]] && command="$bashrun_command_su"

    for word in $command; do
	[[ ! "$word" =~ = ]] && break
    done 

    bashrun_command_word="$word"
}

function §command.executable? {
    
    # check if bashrun_command_word is executable

    §command.get_word

    local word="$bashrun_command_word"
    local type=`type -t $word`

    if [[ "$type" =~ (alias|keyword|builtin) ]]; then
	§debug -v "$word" "->" -v "$type" "->" -g "yes"
	return 0
    fi

    if [[ "$type" == "function" ]]; then
	if §function.exported? $word; then
	    §debug -v "$word" "->" -v "exported function" "->" -g "yes"
	    return 0
	else	    
	    §debug -v "$word" "->" -v "local function" "->" -r "no"
	    return 1
	fi
    fi

    if [[ "$type" == "file" ]]; then
	if type -p $word &> /dev/null; then
	    §debug -v "$word" "->" -v "$type" "-> type -p $word ? ->" -g "yes"
	    return 0
	fi
	if [[ -x $word ]]; then
	    §debug -v "$word" "->" -v "$type" "-> +x $word ? ->" -g "yes"
	    return 0
	fi
    fi

    §debug -v "$word" "->" -r "no"
    return 1
}

function §command.builtin? {

    # check if bashrun_command_word is a shell builtin command

    §command.get_word
    local word="$bashrun_command_word"

    if [[ "$(type -t $word)" == "builtin" ]]; then
	§debug -v "$word" "->" -g "yes"
	return 0
    fi
    §debug -v "$word" "->" -r "no"
    return 1
}

function §command.bookmark? {

    if §bookmarks.seek "$1"; then
	return 0
    fi
    return 1
}

function §command.add_su {

    local user="${1:-root}"
    local stty=""

    # don't wrap in su -c '' twice...
    if [[ -n "$bashrun_command_su" ]]; then
	§debug "already using su"
	return 0
    fi

    # prompt for username
    if [[ "$user" == "--prompt" ]]; then
	until [[ -n "$user" && "$user" != "--prompt" ]]; do
	    tput el
	    tput cr
	    printf '%b' 'Username: '

	    stty="$(stty -g)"
	    stty echo cooked -cbreak

	    read user

	    stty "$stty"
	done
    else
	if §cygwin?; then
	    if [[ "$user" == "root" ]]; then
		user="$(§mode.get_superuser)"
	    fi
	fi
    fi

    # run the command itself in the background
    bashrun_command_su="$bashrun_command"
    bashrun_command="$bashrun_command &> /dev/null &"
    §quote bashrun_command

    # prefix with su command
    bashrun_command="su $user -c $bashrun_command"

    # run the su command in foreground for password entry
    bashrun_execmode="" 
    §debug -v "$bashrun_command"
}

function §command.add_terminal {

    §command.get_word

    local terminal=""
    local terminal_command=""
    local command="$bashrun_original_command"
    local prog="$bashrun_command_word"
    local spec=""
    local found="0"

    if [[ " $bashrun_terminals_used " =~ \ $bashrun_command_word\  ]]; then
     	    §debug "already using" -v "$bashrun_command_word"
     	    return 1
    fi	

    # assume default terminal
    §terminals.seek 'default'

    if [[ -n "$1" ]]; then
	# explicit terminal name given
	if ! §terminals.seek "$1"; then
	    §debug warn "no such terminal:" -v "$term" "(using default)"
	    terminals.seek 'default'
	fi
        
    else
	# match associated terminals
	§terminals.seek_start
	while §terminals.next?; do	    	    

	    eval "$(§terminal.get_match match)"

	    for spec in "${match[@]}"; do

		if [[ "$prog" == "$spec" ]]; then # literal match
		    found=1
		    §debug -v "$prog" "==" -v "$spec" \
			   "->" -c "$(§terminal.get_name)"
		    break;

		elif [[ "$spec" =~ ^/.+/ ]]; then # regexp given
		    spec=${spec:1:${#spec}-2}

		    if [[ "$command" =~ $spec ]]; then # regex match
			found=1
			§debug -v "$prog" "=~" -v "$spec" \
			    "->" -c "$(§terminal.get_name)"
			break;
		    fi
		fi
	    done
	    (( found )) && break
	    §terminals.next
	done
	(( found )) || §terminals.seek 'default'
    fi

    # expand the terminal command
    terminal_command="$(§terminal.get_command)"
    bashrun_command="$(§terminal.expand "$terminal_command" "$bashrun_command")"

    §debug -v "$bashrun_command"

    return 0
}

function §command.add_hold {

    local seconds=${1:-0}
    local method='read -n1'
    §command.get_word

    [[ seconds -gt 0 ]] && method="sleep $seconds"

    bashrun_original_command="$bashrun_command"

    if [[ "$bashrun_command" =~ ^\(.+\)$ ]]; then
	bashrun_command=${BASH_REMATCH[1]}
    fi
    
    if [[ -z "$bashrun_command_hold" ]]; then
        bashrun_command_hold="$bashrun_command";
	bashrun_command="tput civis;(${bashrun_command});$method"
	§debug -v "$bashrun_command"
    else
	§debug "already using hold with" -v "$bashrun_command_hold"
    fi
}

function §command.add_pager {

    §command.get_word

    bashrun_original_command="$bashrun_command"

    if [[ -z "$bashrun_command_page" ]]; then
        bashrun_command_page="$bashrun_command"
	bashrun_command="$bashrun_command | ${PAGER} "
	§debug -v "$bashrun_command"
    else
	§debug "already using pager with" -v "$bashrun_command_page"
    fi
}

function §command.reset {
    bashrun_command=''
    bashrun_command_word=''
    bashrun_command_hold=''
    bashrun_command_page=''
    bashrun_command_su=''
    bashrun_original_command=''
}
