# -*- shell-script -*-

function init_objects {

    source "$bashrun_site/objects"
    §objects.site "$bashrun_site"
    §objects.cache_home "$bashrun_cache_home"
    §objects.data_home "$bashrun_cache_home"
    §objects.namespace "bashrun"
}

function create_modeinfo {

    init_objects

    for file in utils readline message config plugin registry \
	progress templates terminals window modes core; do
	source "$bashrun_site/$file"
    done

    # check rcfile syntax
    errorfile="$bashrun_cache_home/syntax-errors"
    if ! §syntax? "$bashrun_rcfile"; then
	errors="$(<$errorfile)"
	errors="${errors//$'\n'/\\n}"
	§message "Syntax Errors" \
	    "The configuration file contains syntax errors:

             $errors

             Aborting. Please fix and retry."
	
	exit 1
    else
	§debug "using" -c "$(§tilde_path $bashrun_rcfile)"
	source "$bashrun_rcfile"
    fi
    [[ -f "$errorfile" ]] && /bin/rm "$errorfile"
    
    # load modes and templates from configuration file
    §configs.restore_core &>/dev/null

    # load user defined modes
    §configs.collect_user_configs "modes|templates"
    §configs.seek "modes" && §config.restore 
    §configs.seek "templates" && §config.restore 

    # get requested mode
    if ! §modes.seek "$mode"; then
	printf '%s\n' "bashrun2: error: no such mode: \`$mode', exiting..."
	exit 1
    fi
    §mode.write_info
}

function source_window {

    # create the environment §window expects and set wid

    bashrun_mode="$mode"
    source "$bashrun_site/window"

    function §mode.get_geometry { printf '%s' "$geometry"; }    
    function §mode.get_onmap { printf '%s' "$onmap"; }    
    function §mode.get_onunmap { printf '%s' "$onunmap"; }    
    function §mode.get_netwmstate { printf '%s' "$netwmstate"; }    

    §window.id "$wid"
}

function launch {
    
    init_objects

    for file in utils templates terminals; do
	source "$bashrun_site/$file"
    done

    # cleanup possibly stale cache files
    for suffix in wid pid ready abort; do
	if [[ -f "$bashrun_cache_home/$mode-$suffix" ]]; then
	    /bin/rm "$bashrun_cache_home/$mode-$suffix"
	fi
    done
	
    # launch a standard sized terminal in debug mode...
    if (( bashrun_debug )); then
	geometry="80x24"
    fi

    # get first word of terminal line (program binary)
    for prog in $terminal; do break; done

    # check if the terminal program is usable
    if ! type -p $prog &>/dev/null; then
	source $bashrun_site/message
	§message "Error" \
                 "The terminal program \"$prog\" was not found. Please
                  install $prog or use a different terminal installed on
                  your system.

                  The current terminal command template is

                  '$terminal'

                 (as defined by the config directive '+mode $mode
                 --terminal')"

	/bin/rm "$modeinfo"
	exit 1
    fi

    # add terminal options from +mode --options
    termopts+=" $options"

    # create terminal command
    launch="bashrun=1 \
            bashrun_frontend=1 \
            bashrun_mode=$mode \
	    bashrun_feedback=$feedback \
            bashrun_debug=$bashrun_debug \
            $(§terminal.expand "$terminal" \
                 'bash --rcfile __PREFIX__/share/bashrun2/bashrc' \
                 "bashrun2-$mode" "$geometry" \
                 "$font" "$boldfont" "$foreground" "$background" \
                 "$termopts")" 
               
    # trim whitespace
    launch="$(printf '%s\n' "$launch" | sed 's/[ \t]\+/ /g')"

    (( bashrun_debug )) && printf '%s\n' "$launch"

    # file to flag aborts
    abort="$bashrun_cache_home/${mode}-abort"

    # launch the terminal command
    error="$(eval "$launch" 2>&1)" || { 

	   # terminal command failed	
	   touch "$abort"

	   # remove possibly bogus modeinfo
	   [[ -f "$modeinfo" ]] && /bin/rm "$modeinfo"	   

	   # notify user
	   source "$bashrun_site/message"
	   §message "Error" \
                    "Failed to launch terminal. Please make sure that
                     the following terminal command line is correct:

                     $(§terminal.expand "$terminal" '...' \
                        "$mode" "$geometry" "$font" "$boldfont" \
                        "$foreground" "$background" "$termopts")

                     (See the config directive '+mode $mode --terminal')

                     $error"
    } &

    # wait until the terminal window exists...
    wait_until "brwctl bashrun2-$mode &>/dev/null" "[[ -f '$abort' ]]"
    status=$?

    if (( status == 1 )); then
	§debug fail "The terminal window never appeared... giving up."
	exit 1
    fi

    if (( status == 2 )) || [[ -f "$abort" ]]; then
	/bin/rm "$abort" 
	§debug fail "failed" -n "$error"
	exit 1
    fi
    
    # get the window id of the newly created window, update mode info
    # and prepare the §window class
    wid="$(brwctl bashrun2-$mode)"    
    printf "%s\n" "wid=$wid" >> "$modeinfo"
    source_window

    # initially map the newly created window (required in case there
    # is an onmap command)
    §window.map
}

function remote {

    local remote="$bashrun_data_home/$mode-remote"
    local ready="$bashrun_cache_home/${mode}-ready"
    local pidfile="$bashrun_cache_home/${mode}-pid"

    # wait until the remote instance is ready
    if wait_until "[[ -f $ready && -f $pidfile ]]"; then
	
            # put "cwd" "<action> <cmd>" in the "remote" file	
	    printf "$PWD\n$1\n${@:2}\n" > "$remote"

            # send SIGUSR1 to bashrun to pick it up (see §remote)
	    if ! kill -USR1 "$(<$pidfile)"; then
		printf '%s\n' "bashrun2: error: Unable to send SIGUSR1 to bashrun2 process $(<$pidfile)"
		exit 1
	    fi

	    # wait until the remote session has removed the file
	    wait_until "[[ ! -e '$remote' ]]"
    else
	printf '%s\n' "bashrun2: error: bashrun2-$mode not ready"
	exit 1
    fi
    return 0
}

function remote_control_code {
    cat <<EOF
if [[ -n "\$DISPLAY" ]] && ! shopt -p login_shell &>/dev/null; then
  if ! (( bashrun )); then
     remote_control="\${XDG_CACHE_HOME:-\$HOME/.cache}/bashrun2/remote.bash"

     if [[ -f "\$remote_control" ]]; then
       . "\$remote_control"
     fi
     
     unset remote_control
  fi
fi
EOF
}

function version {
    . "$bashrun_site/globals" 2> /dev/null
    printf '%s\n' \
	"bashrun2 $bashrun_version Copyright (C) 2010, 2011 Henning Bekel <h.bekel@googlemail.com>
License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
}

function usage {
    printf '%s\n' "Usage: bashrun2 [options] [command [args]] [-- termopts]

  Options: 

    -v, --version    : show version information and exit
    -h, --help       : show this message and exit
    -m, --mode       : select mode to launch/control
    -d, --debug      : launch in debug mode

    --remote-control : show code to load remote control interface and exit

    -- <termopts>    : terminate argument processing and add the remaining 
                     : arguments to the terminal command line

  Commands: 
       
    show      : show window, move to current desktop and focus
    hide      : hide window 
    toggle    : hide if visible, show if hidden
    smart     : move window up front if not focused/visible, hide otherwise  
    wid       : print terminal window id
    pid       : print process id of bashrun2 session
    debug     : toggle debugging
    reload    : reload configuration
    restart   : restart bashrun2 
    quit,exit : terminate bashrun2

    su <cmd>         : run <cmd> as root, using bashrun for password entry
    do <act> [<cmd>] : remotely invoke <action> [<cmd>]

  Press F1 in bashrun to list the current keybindings.

  For more information, see bashrun2(1) or visit http://bashrun2.googlecode.com
"

}

function wait_until { 

    local wait_condition="${1:-:}"
    local break_condition="${2:-false}"
    local attempts=150

    eval "until $wait_condition; do
        if (( attempts == 0 )); then
	    return 1
	fi
        if $break_condition; then
            return 2
        fi
	((attempts-=1))
	sleep 0.1
    done
    return 0"
    return $?
}
