# -*- shell-script -*-

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

bashrun_engine_busy=0
bashrun_engine_reload=0
bashrun_engine_ready="$bashrun_cache_home/${bashrun_mode}-ready"

bashrun_action=''
bashrun_execmode='&'
bashrun_logfile="${bashrun_logfile:-/dev/null}"
bashrun_cmd_not_found_handle=0
bashrun_action_return_value=-1
bashrun_status="Loading..."
bashrun_lock=0

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

function §engine.init {
    
    §engine.busy

    §separator "Bashrun2 $bashrun_version"

    §debug -v "rcfile" "->" -c "$(§tilde_path $bashrun_rcfile)"

    §progress.update +10 "$bashrun_status [window]"

    # set wid to terminal $WINDOWID
    §window.id $WINDOWID

    # get current readline bindings
    §readline.get_settings
    §readline.get_bindings

    # initialize keymap
    bashrun_keymap="$(§readline.get_setting keymap)"

    # load/restore configuration
    §configs.restore

    # initialize objects
    §progress.update 90 "$bashrun_status [engine]"
    §objects.init "§progress.update +1"

    §progress.update 100 "$bashrun_status [engine]"

    # seek to the current mode
    §modes.seek "$bashrun_mode";

    # enable extdebug and prepare escape from trap
    # (bashdb bugs out if extdebug is set directly from a startup file)
    if [[ ! "$PROMPT_COMMAND" =~ ^trap\ DEBUG ]]; then
	PROMPT_COMMAND="trap DEBUG; shopt -s extdebug; $PROMPT_COMMAND"
    fi

    # init exec mode
    bashrun_execmode='&'

    # install command_not_found_handle
    function command_not_found_handle {
	if (( $(§mode.get_cmdnfh) )); then
	    if §engine.idle?; then
		bashrun_from_cmdnfh=1 §engine.action run 0 "$*"
		return 0
	    fi
	fi
	
	local self="$(§function.code command_not_found_handle)"
	unset -f command_not_found_handle
	$*
	eval "$self"
	return 127
    }
    # create the remote interface
    §remote.interface.create

    # set traps
    trap §engine.shutdown TERM EXIT HUP
    trap §remote.run USR1

    # reset the reload flag
    bashrun_engine_reload=0

    # set ready and idle flags
    §engine.ready
    §engine.idle

    §debug emph -y "done"
    §separator
    §progress.reset
}

function §engine.action {

    local action=$1       # action to perform
    local input=$2        # input override
    local command="$3"    # command override

    §separator "engine $action $command"

    if §actions.seek $action; then

	§engine.busy
	bashrun_rules_applied=0

	bashrun_action=$action

	# overrides
	[[ -z "$input" ]] && input=$(§action.get_input)
	
	§debug "action" -v "$action"

	case $input in
	    
	    1)
	        # accept input via trap
		§debug "setting" -v "DEBUG" -c "trap"
		trap §engine.trap DEBUG
		;; 
	    
	    0)
		# launch directly 
		§engine.launch "$command"
		;;	    
	esac
    else
	§debug fail "no such action:" -v "$action"
    fi   
}

function §engine.trap {
    
    §command.reset

    # the verbatim command line entered
    bashrun_command_line=$(§command.get_line)

    # the command about to be executed, expanded by the shell
    bashrun_command="$BASH_COMMAND"
    bashrun_original_command="$BASH_COMMAND"

    # remove quotes (;|&)
    §command.unquote

    # pass through trap builtin
    if [[ "$bashrun_command" =~ ^trap ]]; then
	§debug -v "trap" -c "removed"
	§engine.busy? && §engine.reset 
	return 0
    fi

    # pass through exit builtin
    [[ "$bashrun_command" =~ ^exit ]] && return 0

    §debug "line   :" -v "$bashrun_command_line"
    §debug "command:" -v "$bashrun_command"

    §engine.launch

    return 1
}

function §engine.launch {

    local command="$1"
    local retval=0
    local status=0

    # command override
    if (( $# == 1 )) || [[ -n "$command" ]]; then
	§debug -c override -v "$command"
	bashrun_command="$command"
	§command.unquote
	
	bashrun_original_command="$bashrun_command"
	bashrun_command_line="$bashrun_command"
    fi
    
    if §actions.seek "$bashrun_action"; then

	if ! §action.available?; then
	    §engine.reset 0
	    return 0
	fi
	
	if §action.function?; then

	    §action.run
	    retval=$bashrun_action_return_value

	    if (( retval != 0 )); then
		(( retval == 1 )) && §engine.reset 
		(( retval == 2 )) && §engine.reset 0
		return 0
	    fi
	fi
    fi

    if [[ -z "$bashrun_command" ]]; then
	§debug "no command(s) to execute" "->" -r "abort"
    else
	§debug "executing" -v "$bashrun_command $bashrun_execmode"
        §engine.execute
    fi

    §engine.reset
    return 0
}

function §engine.execute {

    local ret=0
    local err="$bashrun_cache_home/su-error"

    if [[ "$bashrun_execmode" == "&" ]]; then
	§prepare_logfile
	bash -c "$bashrun_command >> $bashrun_logfile 2>&1 &" > /dev/null 2>&1
    else
	if §action.depends_on? "su"; then 	    
	    # save the current tty settings
	    local stty="$(stty -g)"
	    
	    # prepare tty for su password entry
	    stty echo cooked -cbreak	    
	fi

	bash -c "$bashrun_command"
	ret=$?

	§window.mapped? && §mode.unmap? && §window.unmap

	if §action.depends_on? "su"; then 	    
	    # reset tty settings
	    stty "$stty"

	    if (( ret == 125 )); then
		§message "Error" "su: incorrect password"
	    fi
	fi
    fi
}

function §engine.reset {

    local unmap=${1:-1}

    # reset action return value
    bashrun_action_return_value=-1

    # reset rules
    bashrun_rules_applied=0

    # assume execmode background
    bashrun_execmode="&"

    # reset terminal
    §terminals.seek default
    
    # disable action api here to allow nested actions
    §action.api.disable 

    # unmap the window if requested/necessary
    if (( unmap )); then 
	if §mode.unmap?; then
	    §window.unmap
	fi
    fi

    §command.reset

    §engine.idle
    
    §debug -c "reset"

    §separator       

    (( bashrun_engine_reload )) && §engine.reload
}

function §engine.reload {

    §separator "reloading engine..."
    §window.map

    /bin/rm $bashrun_engine_ready &>/dev/null

    §objects.clear    
    §engine.init

    §window.map
    
    (( bashrun_debug == 0 )) && tput reset
    
    §separator "engine reloaded"
}

function §engine.shutdown { 

    local suffix file

    §debug -y "shutting down..."

    # remove this instance from registry
    §registry.remove

    # remove ready flag, remove mode-info
    for suffix in ready info; do
	file="$bashrun_cache_home/${bashrun_mode}-$suffix"
	[[ -f "$file" ]] && /bin/rm "$file"
    done

    # remove plugin check and errors file
    /bin/rm "$bashrun_plugins_checked" &>/dev/null

    # remove remote command file (required for remote quit)
    /bin/rm "$bashrun_remote" &>/dev/null

    §debug "exit"
    exit 0
}    

function §engine.busy {
    bashrun_engine_busy=1
}

function §engine.idle {
    bashrun_engine_busy=0
}

function §engine.busy? { (( bashrun_engine_busy )); }

function §engine.idle? { ! (( bashrun_engine_busy )); }

function §engine.ready {
    
    if (( bashrun_frontend )); then
	touch "$bashrun_engine_ready"
    fi
}    

function §engine.ready? {
    [[ -f "$bashrun_engine_ready" ]]
}
