#!/bin/sh

PATH="/usr/lib/alterator-x11:$PATH"

DATADIR="/usr/share/alterator-x11"
TICKETDIR="/var/lib/alterator/tickets"

XORGCONFIG_MAIN="/etc/X11/xorg.conf"
XORGCONFIG_TEMPLATE="$DATADIR/xorg.conf"
XORGCONFIG_WORKCOPY="/etc/X11/xorg.conf.alterator"

XORGDRV_DIR="$(getconf LIBDIR)/X11/modules/drivers"

XCONFTOOL="/usr/bin/xconf"
SETUPDRVTOOL="/usr/bin/x11setupdrv"
XTESTTOOL="/usr/bin/xtest_wrapper"

po_domain="alterator-x11"

set -f
. alterator-sh-functions
. shell-regexp

#### xorg config functions

xorg_config_name()
{
	if [ -f "$XORGCONFIG_WORKCOPY" ] ;then
		echo "$XORGCONFIG_WORKCOPY"
	else
		echo "$XORGCONFIG_MAIN"
	fi
}

made_workcopy()
{
	if [ -f "$XORGCONFIG_MAIN" ] ;then
		cp "$XORGCONFIG_MAIN" "$XORGCONFIG_WORKCOPY"
	else
		cp "$XORGCONFIG_TEMPLATE" "$XORGCONFIG_WORKCOPY"
		mouse_autosetup -c "$XORGCONFIG_WORKCOPY" xorg
		video_autosetup "$XORGCONFIG_WORKCOPY"
	fi
}

sure_workcopy()
{
	[ -f "$XORGCONFIG_WORKCOPY" ]  || made_workcopy
}


clear_workcopy()
{
	[ -f "$XORGCONFIG_WORKCOPY" ] && rm -f "$XORGCONFIG_WORKCOPY"
}

commit_workcopy()
{
    [ -f "$XORGCONFIG_WORKCOPY" ] && mv -f "$XORGCONFIG_WORKCOPY" "$XORGCONFIG_MAIN"
    "$SETUPDRVTOOL" "$XORGCONFIG_MAIN" >&2 #setup correct GL symlinks for the current config file
}

###helper functions

out_option()
{
    [ -n "$2" ] && printf '%s "%s"' "$1" "$2"
}

in_option()
{
    sed -nr "s,^$1[[:space:]],,p"
}

clear_ddc()
{
    ddcclean
}


#read autodetect information
read_autodetect_data()
{
	#video data
	local data="$(video_scan)"
	auto_cardname="$(echo "$data"|in_option cardname)"
	auto_xdepth="$(echo "$data"|in_option xdepth)"

	auto_xdriver="$(echo "$data"|in_option xdriver)"	
	auto_xdrivername="$(echo "$data"|in_option xdrivername)"

	#monitor data
	auto_monitor="$(monitor_scan)"

	[ -n "$auto_monitor" ] || auto_monitor="Monitor 1024x768"
	[ -n "$auto_xdriver" ] || auto_xdriver="vesa"
	
	#recommended resolution
	local size="$(ddcsize)"
	if [ -n "$size" ];then
	    auto_xresolution="$(ddcreslist|ddcresbest "${size% *}" "${size#* }")"
	fi
	[ -n "$auto_xresolution" ] || auto_xresolution="auto"
}

#### get functions
get_monitor()
{
    local monitor="$($XCONFTOOL -n "$1"| cut -f1 -d'|')"
    [ -n "$monitor" ] || monitor="$auto_monitor"

    echo "$monitor"
}

get_first_monitor()
{
    mondrv |
	grep  -m1 "^$(quote_sed_regexp "$1");"|
	cut -f2 -d';'|
	sed -r 's,^[[:space:]]*,,'
}

get_vendor()
{
    mondrv |
	grep -m1 "[^;]\+;[[:space:]]*$(quote_sed_regexp "$1");"|
	cut -f1 -d';'
}

#### ticket functions
clear_ticket()
{
    find "$TICKETDIR"  -mindepth 1 -maxdepth 1 -type f -name 'xorg-ticket-*' -delete
}

find_ticket()
{
    find "$TICKETDIR"  -mindepth 1 -maxdepth 1 -type f -name 'xorg-ticket-*' -print -quit
}

make_ticket()
{
    [ -d "$TICKETDIR" ] || install -d -m755 "$TICKETDIR"

    name="$TICKETDIR/xorg-ticket-$(uuidgen)"
    
    cat>"$name"<<EOF
#!/bin/sh
LANG=${in_language%%;*}.utf8 "$XTESTTOOL" "$XORGCONFIG_WORKCOPY"
EOF
    chmod 755 "$name"
    echo "$name"
}

get_ticket()
{
    local ticket="$(find_ticket)"

    [ -n "$ticket" ] || ticket="$(make_ticket)"

    echo "${ticket##*/}"
}


#### read functions

read_firefox()
{
    local ticket="$(get_ticket)"

    out_option "alt-exec-description" "`_ "Test current display settings"`"
    out_option "alt-exec-error-message" "`_ "Test failed"`"
    out_option "alt-exec-command" "${ticket};`_ "Test"`"
}

#### write functions

#### list functions
print_recommended()
{
    [ "$1" = "$2" ] && printf -- ' - %s' "`_ "recommended"`"
}

print_xdepth()
{
    write_enum_item "$1" "$2$(print_recommended "$1" "$3")"
}

list_xdepth()
{
    local xdriver="$($XCONFTOOL -d "$1")"
    [ -n "$xdriver" ] || xdriver="$auto_xdriver"

    local xdepth_list=$(echo "$xdriver" | vcinfo | sed -nr '/^xdlist/ s,xdlist[[:space:]]+,,p')
    local recomm_xdepth=$(echo "$xdriver" | vcinfo | in_option xdepth)

    for i in $xdepth_list; do
	case $i in
	    8) print_xdepth 8 "`_ "256 colors (8 bit)"`" $recomm_xdepth;;
	    15) print_xdepth 15 "`_ "32 thousand colors (15 bits)"`" $recomm_xdepth ;;
	    16) print_xdepth 16 "`_ "65 thousand colors (16 bits)"`" $recomm_xdepth ;;
	    24) print_xdepth 24 "`_ "16 million colors (24 bits)"`" $recomm_xdepth ;;
	    32) print_xdepth 32 "`_ "4 billion colors (32 bits)"`" $recomm_xdepth ;;
	     *) print_xdepth $i "$i `_ "bits"`" $recomm_xdepth ;;
	esac
    done
}

list_xresolution()
{
    local res="$(ddcreslist)"
    [ -n "$res" ] || res="$(cat "$DATADIR/resolutions")"

    write_enum_item "auto" "`_ "automatically"`"
    for i in $res;do
	write_enum_item "$i" "$i$(print_recommended "$i" "$auto_xresolution")"
    done
}

list_xdriver()
{
    local IFS='	'
    find "$XORGDRV_DIR" -name '*_drv.so'|
	sed -r 's,.*/([a-z0-9]+)_drv\.so$,\1,'|
	video_drivers|
	sort|
	while read driver description rest; do
	    write_enum_item "$driver" "$driver - $description$(print_recommended "$driver" "$auto_xdriver")"
	done
}

list_model()
{
    local config="$(xorg_config_name)"
    local monitor="$(get_monitor "$config")"
    local vendor="$(get_vendor "$monitor")"
    local IFS=";" #for write_enum_item

    if [ -n "$vendor" ]; then
	mondrv|
	    grep "^$(quote_sed_regexp "$vendor");"|
	    cut -f2 -d';'|
	    sort -u|
	    sed -r 's,^[[:space:]]*,,'|
	    write_enum_item
    else
	write_enum_item "$monitor"
    fi
}

list_vendor()
{
    local IFS=";" #for write_enum_item
    write_enum_item "auto" "`_ "Automatically detected"`"
    mondrv|
	cut -f1 -d';'|
	sort -u|
	write_enum_item
}

#### exit handler and initialization

exit_handler()
{
	trap - TERM HUP EXIT

	[ -f "$XORGCONFIG_MAIN" ] && "$SETUPDRVTOOL" >&2
	clear_workcopy
	clear_ddc
	clear_ticket
}

trap exit_handler TERM HUP EXIT

[ -x /usr/sbin/x11presetdrv ] && /usr/sbin/x11presetdrv >&2 ||: #sure we use right nvidia.xinf files
clear_workcopy #remove workcopy
clear_ddc #remove ddc cache
clear_ticket
read_autodetect_data #detect video hardware


on_message()
{
	case "$in_action" in
		list)
		    local config="$(xorg_config_name)"
		    echo '('
			case "${in__objects##*/}" in
			    avail_xdepth)
				list_xdepth "$config"
				;;
			    avail_xresolution)
				list_xresolution
				;;
			    avail_xdriver)
				list_xdriver
				;;
			    avail_model)
				list_model
				;;
			    avail_vendor)
				list_vendor
				;;
			esac
		    echo ')'
		    ;;
		read)
			local config="$(xorg_config_name)"
			echo '('
			case "$in__objects" in
			    monitor)
				local monitor=$(get_monitor "$config")
				out_option vendor "$(get_vendor "$monitor")"
				;;
			    *)
				read_firefox

				#autodetect
				out_option auto_cardname "$auto_cardname"
				out_option auto_monitor "$auto_monitor"

				#config
				[ -f "$config" ] || printf 'config_status "(%s)"\n' "`_ "config file doesn\'t exist"`"

				local xdriver="$($XCONFTOOL -d "$config")"
				local xdepth="$($XCONFTOOL -c "$config")"
				local xresolution="$($XCONFTOOL -r "$config")"

				#fill missing values using autodetect data
				[ -n "$xdriver" ] || xdriver="$auto_xdriver"
				[ -n "$xdepth" ] || xdepth="$auto_xdepth"
				[ -n "$xresolution" ] || xresolution="$auto_xresolution"

				#calculate driver name
				out_option monitor "$(get_monitor "$config")"
				out_option xdriver "$xdriver"
				out_option xdrivername "$(echo "$xdriver"|video_drivers|cut -f2)"
				out_option xdepth "$xdepth"
				out_option xresolution "$xresolution"
				;;
			esac
			echo ')'
			;;
		write)
			sure_workcopy
			local config="$(xorg_config_name)"
			
			case "$in__objects" in
			    /)
				[ -n "$in_monitor" ] && monitor_setup "$in_monitor" "$config"
				[ -n "$in_xdepth" ] && $XCONFTOOL -C "$in_xdepth" "$config" "$config"
				[ -n "$in_xresolution" ] && resolution_setup "$in_xresolution" "$config"

				[ "$in_commit" = '#f' -o "$in_async" = 'yes' ] || commit_workcopy
				;;
			    driver)
				if [ -n "$in_xdriver" ]; then 
				    video_setup "$in_xdriver" "$config"
				    local recomm_xdepth=$(echo "$in_xdriver" | vcinfo | in_option xdepth)
				    [ -n "$recomm_xdepth" ] && 
				    $XCONFTOOL -C "$recomm_xdepth" "$config" "$config"
				fi
				;;
			    monitor)
				    if [ "$in_vendor" = "auto" ];then
					    monitor="$auto_monitor"
				    else
					    monitor="$(get_first_monitor "$in_vendor")"
				    fi
				    [ -n "$monitor" ] && monitor_setup "$monitor" "$config"
				;;
			    test)
				if [ ! -f "$XORGCONFIG_WORKCOPY" ];then
				    write_error "`_ "no workcopy was found"`"
				    return;
				fi
				if ! LANG=${in_language%%;*}.utf8 $XTESTTOOL "$XORGCONFIG_WORKCOPY"; then
				    write_error "`_ "X11 test failed"`"
				    return;
				fi
				;;
			esac
			write_nop
			;;

		*)
			echo '#f'
			;;
	esac
}

message_loop
