#!/bin/bash
##################################################################################
## Bashish, a console theme engine
## Copyright (C) 2010 Thomas Eriksson
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
##################################################################################
##
## THIS IS BASHISH2. YOU WILL BE ASSIMILATED
##
######################################################

## _bashish_module is a function that reads and executes shell script 
## parts located in $BASHISHDIR/modules/sh/
function _bashish_module
{
	. "$BASHISHDIR"/main/terminal/$1
}


## to reduce memory usage in the themecap variables, we need to have
## incorrect indenting here

## INCORRECT INDENTING STARTS HERE ##

TERMNAME=$TERM

## themecap files, defines a set of theming capabilities for terminals
## each themecap entry is a function residing in a file in
## $BASHISHDIR/modules/sh/engine which have the same name as it's function
## 


## This section is for terminals following the ANSI X3.64, ISO DP-6429, 
## and ECMA-48 standards
##
## the terminals support colors and cursor positioning (title)
## this themecap is also backwards compatible with some broken terminals
## not implementing cursor restore.
function themecap_ansi
{
	TERMNAME=ansi
	THEMECAP="\
	_bashish_generic_winch\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar"
}

## vt52
function themecap_vt52
{
	TERMNAME=vt52
	THEMECAP="\
	_bashish_generic_winch\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar"
}

## cmdtool
## ancient Sun NeWS and XView Terminal
function themecap_cmdtool
{
	TERMNAME=cmdtool
	THEMECAP="\
	_bashish_generic_winch\
	_bashish_cmdtool_printtitle\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar"
}
## gnome-terminal doesn't make use of control sequence characters to control
## it's behaviour, instead it uses an external process to communicate with it
## in this case gconftool-2
function themecap_gnometerminal
{
TERMNAME=gnome-terminal
THEMECAP="\
	_bashish_vt100_sane\
	_bashish_gnome-terminal_winch\
	_bashish_xterm_printtitle\
	_bashish_vt100_reverse\
	_bashish_gnome-terminal_properties\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar"
}

## BeOS Terminal, simple xtermish
function themecap_beterm
{
TERMNAME=beterm
THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_beterm_properties\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide\
	_bashish_generic_winch"
}

## konsole is similar to gnome-terminal in it's not using control sequence
## characters to control it's apperance, instead it uses dcop, which due to
## the pipe feature of "dcop" is REALLY fast! :)
function themecap_konsole
{
	TERMNAME=konsole
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_konsole_properties\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_generic_winch\
	_bashish_vt100_posthide"
}

## Linux console
## supports font, ansicolors (with the exceptions of WHITE and BLACK)
## foreground background colors
function themecap_linux
{
	TERMNAME=linux
	THEMECAP="\
	_bashish_generic_winch\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_linux_ansi\
	_bashish_linux_color\
	_bashish_linux_font\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide"

}

## vt100 has cursor positioning (which makes for a nice title) but no colors
## only for very old terminal emulators or real terminals which do not support
## colors
function themecap_vt100
{
	themecap_ansi
	TERMNAME=vt100
}

## Eterm
## Very powerful theming terminal, Bashish ignores Eterm's own theme format
function themecap_xterm-Eterm
{
	TERMNAME=xterm-Eterm
	TERMNAME=xterm-rxvt 
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_rxvt_color\
	_bashish_eterm_ansi\
	_bashish_xterm_font\
	_bashish_xterm_geometry\
	_bashish_eterm_image\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_xterm_winch\
	_bashish_vt100_posthide"

}

## rxvt section
## rxvt was supposed to be an XTerm clone, however it differs from XTerm
## notably in the XTerm color sequencies and it's wider range of theming eg.
## image background
## 
## the rxvt project does nowadays not seem very active but instead some forks 
## of it has become very popular, notably aterm and Eterm
## 
## rxvt has been ported to various non-unix operationg system where the font
## changing is not supported.
function themecap_xterm-rxvt
{
	TERMNAME=xterm-rxvt 
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_rxvt_color\
	_bashish_xterm_ansi\
	_bashish_xterm_font\
	_bashish_xterm_geometry\
	_bashish_rxvt_image\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_xterm_winch\
	_bashish_vt100_posthide"
}


## rxvt-unicode/urxvt is a powerful clone of the rxvt terminal
## to Bashish, it differs mainly in the extended font capabilities
## where one can specify different fonts for different parts of the 
## unicode character table.
## the Bashish code for urxvt defaults to scalable fonts if avaliable.
function themecap_xterm-urxvt
{
	TERMNAME=xterm-rxvt 
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_rxvt_color\
	_bashish_xterm_ansi\
	_bashish_urxvt_font\
	_bashish_xterm_geometry\
	_bashish_rxvt_image\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_xterm_winch\
	_bashish_vt100_posthide"
}


function themecap_xterm-rxvt-nofont
{
	TERMNAME=xterm-rxvt-nofont
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_rxvt_color\
	_bashish_xterm_ansi\
	_bashish_rxvt_image\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide\
	_bashish_generic_winch"
}

function themecap_xterm_dtterm
{
	## CDE Terminal
	TERMNAME=xterm-dtterm
	## icon!!
	THEMECAP="\
	_bashish_generic_winch\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide"
}

## xterm-generic
## this is probably the most common software emulator
## it somewhat reassembles a VT102 with xterm title sequence
## putty, BeTerm, PhTerm (QNX)
function themecap_xterm-generic
{
TERMNAME=xterm-generic
THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide\
	_bashish_generic_winch"
}


## XTerm -- http://dickey.his.com/xterm/xterm.html
## XTerm is the classic terminal emulator for X, it has very accurate 
## emulation and supports a lot of theming features.
## bashish uses control sequencies to control it's apperance which means
## bashish need to keep track of state to make the theme changing as fast as
## possible
function themecap_xterm-xterm
{
	TERMNAME=xterm-xterm
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_xterm_color\
	_bashish_xterm_ansi\
	_bashish_xterm_font\
	_bashish_xterm_geometry\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide\
	_bashish_xterm_winch"

}

## old XTerm versions
## XTerm versions from early X11R6 are supposed to be supported here.
## they differ a bit from the new versions with the absense of 
## font changing and buggy/nonexistant ansi color setting
function themecap_xterm-old
{
	TERMNAME=xterm-xterm-old
	THEMECAP="\
	_bashish_vt100_prehide\
	_bashish_vt100_sane\
	_bashish_xterm_printtitle\
	_bashish_xterm_color\
	_bashish_xterm_ansi\
	_bashish_xterm_font\
	_bashish_generic_bulkprint\
	_bashish_generic_cleanvar\
	_bashish_vt100_posthide\
	_bashish_xterm_winch"
}

### INCORRECT INDENDING STOPS HERE ###

	## xterm and vt100 is commonly used as TERM variables
	case "$TERM" in
	sun-cmd)
		## OpenWindows/NeWS terminal emulators: cmdtool, shelltool
		themecap_cmdtool
	;;
	vt52)
		themecap_vt52
	;;
	vt1*)
		## VT100 does not have colors
		themecap_vt100
	;;
	vt220|vt320|pcvt*|vt*|ansi*|con80x*|con100x*|con132x*|console|sun*|386at|AT386|qnx*)
		themecap_ansi
		case "`uname 2>/dev/null`" in
		UWIN*)
			## AT&T U/WIN
			themecap_vt100-uwin;;
		esac
	;;
	nixterm)
	## dumb terminals
		: TERMNAME=dumb
	;;
	beterm)
		## BeOS terminal
		themecap_beterm;;
	qansi*)
		## BeOS and QNX supports title
		themecap_xterm-generic
	;;
	sun-cmd)
		## OpenWindows/NeWS terminal emulators: cmdtool, shelltool
		themecap_cmdtool
	;;
	dtterm)
		## XTerm-old with bitmap icon
		themecap_xterm_dtterm
	;;
	X-hpterm)
		## HP Term, not a member of the XTerm family
		themecap_hpterm
	;;
	kterm|aixterm)
		## AIXterm and kanjii terminal emulator
		themecap_xterm-old
	;;
	linux|lx*)
		themecap_linux
	;;
	ibm-3278-5-e|ibm-3279-5-e)
		## x3270 supports xterm title
		themecap_xterm-generic
	;;
	*xterm*|rxvt|Eterm|rxvt-unicode)
		## default to title changing only
		themecap_xterm-generic
		
		## rxvt runs on win32 without font support
		test "$COLORTERM" = rxvt && themecap_xterm-rxvt-nofont
		
		## gnome-terminal
		test "x${COLORTERM}" = xgnome-terminal && themecap_gnometerminal

		## detect terminal by it's window class name as seen by xprop.
		test "$WINDOWID"&&case "`xprop -id $WINDOWID 2>/dev/null|grep \"WM_CLASS(STRING)\" 2>/dev/null`" in
			*Eterm*) themecap_xterm-Eterm
				#test -n "$ETERM_OLD" && TERMNAME=xterm-Eterm_old
				;;
			*urxvt*) themecap_xterm-urxvt;;
			*xvt*|*wterm*|*aterm*) themecap_xterm-rxvt;;
			*konsole*) themecap_konsole;;
			*cxterm*) ## is this correct?
			themecap_xterm-generic;;
			*mlterm*) themecap_xterm-rxvt-nofont;;
			*XTerm*) themecap_xterm-xterm
				test "x$XTERM_VERSION" = x&&themecap_xterm-old
				;;
			*)
			case `xwininfo -id $WINDOWID 2>/dev/null` in
			*\(has\ no\ name\)*)
				TERMNAME=xterm-generic
				## gnome-terminal has no window name
				## so we also have to check the $COLORTERM variable
				## note that XTerm doesn't set the COLORTERM 
				## and thus a "(has no name)" window must be identified
				test "$COLORTERM" = gnome-terminal && \
					themecap_gnometerminal
			esac
		esac
	esac
	
	## GSH as found at http://personal.atl.bellsouth.net/v/c/vcato/gsh/
	## an XML-aware Tcl/Tk based terminal emulator
	test "$COLORTERM" = gsh && themecap_xterm-generic
	
	## recent versions of Gnome-terminal sets the COLORTERM
	test "x$COLORTERM" = xgnometerminal && themecap_xterm-generic
	
	## Mozilla XML term, currently unsupported
	test "$LTERM_COOKIE" && themecap_xterm-generic
	
	## Textmode Window Manager
	test "$TWDISPLAY" && themecap_xterm-generic
	
	## is a special case for ssh really needed?
	#test "$SSH_CLIENT$SSH_CONNECTION$SSH_TTY" && {
	#	case "$TERM" in
	#	Eterm)
	#		TERMNAME=xterm-Eterm_nofont
	#	;;
	#	xterm)
	#	if test $COLORTERM = rxvt ;then
	#		TERMNAME=xterm-rxvt_nofont
	#	else
	#		## here we cannot omit unsupported features of
	#		## xterm-generic terminals, since it's impossible 
	#		## to detect correct terminal
	#		TERMNAME=xterm-xterm_nofont
	#	fi
	#	;;
	#	linux)
	#		TERMNAME=linux_nofont
	#	esac
	#}


	
	## multi-byte terminals as 'mlterm' and 'cxterm'
	## supports rxvt background color but no font changing
	test -n "$MLTERM" && themecap_xterm-rxvt-nofont
	
	## powershell is an older gtk1 terminal emulator
	test "x$POWERSHELL" != x && themecap_xterm-generic
	
	## Terminal in Mac OS X, xterm-generic until some 
	## AppleScript Wizard can implement some magic for it
	test "$TERM_PROGRAM" = "Apple_Terminal" && themecap_xterm-generic
	
	## YaKuake - a roll-down terminal at the top which uses the Konsole kpart
	test "x${DCOP_YAKUAKE_SESSION}" != x && themecap_konsole
	
	## GNUStep Terminal
	test "$TERM_PROGRAM" = "GNUstep_Terminal" && themecap_xterm-generic

	for UNSET in vt52 vt100 ansi linux xterm_dtterm xterm-generic xterm-rxvt-nofont xterm-old gnometerminal 
		do
		unset -f themecap_$UNSET
	done
#fi

## load all modules specified in $THEMECAP
#local LOAD
for LOAD in $THEMECAP
do
	_bashish_module engine/$LOAD
done

########################################################
##
## This is the theme loader for bashish
##
########################################################

## dummy default theme options
_bashish_theme_defaults () { :;}

## dummy prompt theme
_bashish_theme_prompt () { :;}

## dummy prompt overrides
_bashish_theme_overrides () { :;}
	
## load the theme defaults to memory
test -f "$HOME"/.bashish/defaults/theme && . "$HOME"/.bashish/defaults/theme

#local BASHISH_THEME

## load the prompt theme to memory
test -f "$HOME"/.bashish/prompt/theme && . "${HOME}"/.bashish/prompt/theme

## test if the loaded theme is a valid bashish2 theme, elsewise it will not 
## be loaded
test "x$BASHISH_THEME" != x &&{
	## this creates the function _bashish_theme_prompt() which calls
	## the selected bashish theme function (very fast)
	eval "function _bashish_theme_prompt { _bashish_theme_$BASHISH_THEME;}"
}
unset BASHISH_THEME
## load the theme overrides to memory
test -f "$HOME"/.bashish/overrides/theme && . "${HOME}"/.bashish/overrides/theme

## declare variables
#local APPDIR APPNAME IFS

## this is a helper function commonly used to locate a file in
## the three btdirs
function _bashish_whichbtdir
{   
	local WHICHBTDIR
	for WHICHBTDIR in "$HOME/.bashish/override" "$BTDIR" "$HOME/.bashish/fallback"
	do
		test -f "$WHICHBTDIR/$1" && { printf "$WHICHBTDIR" ; return 0; }
	done
}

## _bashish_brefresh is the main themeing function called when theme
## settings is to be applied to a terminal
function _bashish_brefresh
{
	if test "x${BASHISH_ARGV[0]}" != x; then
		## set BTDIR to APPDIR
		local BTDIR="$HOME"/.bashish/app/${BASHISH_ARGV[0]##*/}
	else
		## $BTDIR points to the theme dir
		local BTDIR="$HOME"/.bashish/prompt/
	fi
	## load default theme options
	_bashish_theme_defaults

	## load prompt theme
	_bashish_theme_prompt
	
	test "x${BASHISH_ARGV[0]}" != x && {
		## load application theme
		_bashish_btapp_${BASHISH_ARGV[0]##*/}
	}

	## override theme options
	_bashish_theme_overrides

	##################################################################
	
	## do not make FUNCTION global
	local FUNCTION
	
	## load theme functions
	for FUNCTION in $THEMECAP; do
		$FUNCTION
	done
}

## this script is not intended for interactive use
## write the pid of this process

unset BTAPP BASHISH_ARGV[*] BASHISH_ARGC EVAL
unset BTAPP BASHISH_ARGV ARGV EVAL
_bashish_brefresh

: >"$HOME/.bashish/tmp/${TTY##*/}/sync"

printf "$$" 1> "$HOME"/.bashish/tmp/${TTY##*/}/pid

## load each btapp alias/function
for APPDIR in "$HOME"/.bashish/app/* 
do
	test "x${APPDIR##*/}" = "x*"&& break
	## set the the name of each application to $APPNAME
	IFS=/
	for APPNAME in $APPDIR
	do
		:
	done

	## clean functions variables and aliases that may interfere with
	## the theme setting
	unset -f APPNAME 2>/dev/null
	unalias APPNAME 2>/dev/null
	unset BASHISH_NOAUTO IFS

	## load theme into memory
	. $APPDIR/theme

	
	## load a function pointing to the real theme function
	eval $(printf "function _bashish_btapp_$APPNAME { _bashish_theme_$BASHISH_THEME;}" )
done
unset APPDIR APPNAME



## clean up bashish zombie processes that are connected to disconnected ttys
for TTYS in "$HOME"/.bashish/tmp/*
do
	test -O "/dev/${TTYS##*/}" -o -O "/dev/pts/${TTYS##*/}"||{
	read TTYPID <"${TTYS}/pid"
	kill -9 "$TTYPID"
	rm -rf ${TTYS}
	}
## the zombie killings ain't pretty, hide from kids
done  1>/dev/null 2>/dev/null
unset TTYS

## Cygwin compatibility code
PROCEXIST=0
test -f "$HOME/.bashish/tmp/${TTY##*/}/pid" && {
	read BASHISH_SUBPROC <"$HOME"/.bashish/tmp/"${TTY##*/}"/pid

	ps "$BASHISH_SUBPROC" 2>/dev/null 1>/dev/null && PROCEXIST=1
}

## ps usage which at least works with linux and cygwin
if test "$PROCEXIST" = 1
then
	## kill old process
	kill $BASHISH_SUBPROC 2>/dev/null
else
	mkdir -p "${IPCDIR}/"
	test -p "$IPCDIR/subproc" || mkfifo "$IPCDIR/subproc"
fi

## main loop
## wait for input from FIFO, execute input, loop
while true
do
## until

	until test x$BTAPP != x
	do
	unset BTAPP BASHISH_ARGV ARGV EVAL

	## test if fifo is avaliable
	test -p "$HOME"/.bashish/tmp/${TTY##*/}/subproc||exit 1
	read EVAL <"$HOME/.bashish/tmp/${TTY##*/}/subproc"
	eval $EVAL
	_bashish_brefresh
	sleep 1
	done

	until test "x${BASHISH_ARGV[0]}" = x
	do
	unset BTAPP BASHISH_ARGV[*] EVAL
	## test if fifo is avaliable
	test -p "$HOME"/.bashish/tmp/${TTY##*/}/subproc||exit 1
	read EVAL <"$HOME/.bashish/tmp/${TTY##*/}/subproc"
	eval $EVAL
	done

	_bashish_brefresh
	unset BTAPP BASHISH_ARGV[*] BASHISH_ARGC EVAL
	sleep 1
done
