#!/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"

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
    x11_autosetup "$XORGCONFIG_WORKCOPY"
  fi
}

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


clear_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
  # remove config-x11's backup to prevent him from overwriting new xorg.conf
  rm -rf /tmp/alterator/config-x11.backup
}

###helper functions

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

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


# xdepth and xres depends on selected driver
get_auto_xdepth(){
  local xdriver="$1"
  echo "$xdriver" | vcinfo | in_option xdepth
}

get_auto_xres(){
  local xdriver="$1"
  if [ "$xdriver" = "fbdev" -a -c "/dev/fb0" ]; then
    echo "$(fbresolution:-"auto")"
    return
  fi
  # recommended resolution
  local size="$(ddcsize)"
  if [ -n "$size" ];then
    auto_xresolution="$(ddcreslist|ddcresbest "${size% *}" "${size#* }")"
  fi
  [ -n "$auto_xresolution" ] || auto_xresolution="auto"
  echo "$auto_xresolution"
}

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

	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"

	local fbres=
	[ -c "/dev/fb0" ] && fbres=$(fbresolution)
	if [ -z "$auto_xdriver" -a -n "$fbres" ]; then
	   auto_xdriver="fbdev"
	   return
	fi

	[ -n "$auto_xdriver" ] || auto_xdriver="vesa"
}

#### 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=$(get_auto_xdepth "$xdriver")

    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")"

    local recommended_xres=$(get_auto_xres )
    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,'|
	vcdb | cut -f2,3,4 | 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

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

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

#### exit handler and initialization

exit_handler()
{
	trap - TERM HUP EXIT

	[ -f "$XORGCONFIG_MAIN" ] && "$SETUPDRVTOOL" >&2
	clear_workcopy
	ddcclean
	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_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")"
				;;
			    *)
				[ -f "/tmp/alterator/config-x11" ] && echo 'config_x11 #t'

				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
				if [ -z "$xdriver" ]; then
				  xdriver="$auto_xdriver"
				  video_setup "$xdriver" "$config"
				fi
				if [ -z "$xdepth" ]; then
				  xdepth="$(get_auto_xdepth "$xdriver")"
				  xconf -C "$xdepth" "$config" "$config"
				fi
				if [ -z "$xresolution" ]; then
				  xresolution="$(get_auto_xres "$xdriver")"
				  resolution_setup "$xresolution" "$config"
				fi

				#calculate driver name
				out_option monitor "$(get_monitor "$config")"
				out_option xdriver "$xdriver"
				out_option xdrivername "$(echo "$xdriver" | vcdb | cut -f3)"
				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"
				    $XCONFTOOL -C "$(get_auto_xdepth "$in_xdriver")" "$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

				# we can't run nv under nvidia and vice versa
				local old_drv=  #"$(xconf -d "$XORGCONFIG_MAIN")"
				# in installer we can't find old driver in $XORGCONFIG_MAIN...
				cat /proc/`pidof X`/maps | grep -q nvidia_drv.so && old_drv=nvidia
				cat /proc/`pidof X`/maps | grep -q nv_drv.so && old_drv=nv
				local new_drv="$(xconf -d "$XORGCONFIG_WORKCOPY")"
				local old_new="$old_drv $new_drv"
				if [ "$old_new" = "nv nvidia" -o "$old_new" = "nvidia nv" ]; then
				  write_error "`_ "Test disabled, because nv and nvidia drivers can not work on your video card simultaneously. Probably if one of them works fine now then the other one would work fine too."`"
				  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
