#!/usr/bin/env bash
# tweak - change various non-exposed settings

. lib.bash || exit

settings='
{
	"gnome": {
		"antialiasing": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "font-antialiasing",
			"type": "string"
		},
		"automount": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.media-handling",
			"key": "automount",
			"type": "bool"
		},
		"battery-perentage": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "show-battery-percentage",
			"type": "bool"
		},
		"gtk-theme": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "gtk-theme",
			"type": "string"
		},
		"hinting": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "font-hinting",
			"type": "string"
		},
		"icon-theme": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "icon-theme",
			"type": "string"
		},
		"rgba": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "font-rgba-order",
			"type": "string"
		},
		"text-scale": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.interface",
			"key": "text-scaling-factor",
			"type": "float"
		},
		"touchpad-dwt": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.peripherals.touchpad",
			"key": "disable-while-typing",
			"type": "bool"
		},
		"touchpad-speed": {
			"method": "gsettings",
			"schema": "org.gnome.desktop.peripherals.touchpad",
			"key": "speed",
			"type": "float"
		}
	},
	"builder": {
		"line-height": {
			"method": "gsettings",
			"schema": "org.gnome.builder.editor",
			"key": "line-height",
			"type": "float"
		}
	},
	"gte": {
		"line-height": {
			"method": "gsettings",
			"schema": "org.gnome.TextEditor",
			"key": "line-height",
			"type": "float"
		}
	},
	"xfce": {
		"gtk-theme": {
			"method": "xfconf",
			"channel": "xsettings",
			"property": "/Net/ThemeName",
			"type": "string"
		},
		"wm-theme": {
			"method": "xfconf",
			"channel": "xfwm4",
			"property": "/general/theme",
			"type": "string"
		}
	}
}
'

require() {
	if [[ $font && $font != '-' ]]; then
		case $1 in
		gtk)
			re=' [[:digit:]]+$'
			eg='Cantarell 11'
			[[ $font =~ $re ]];;
		esac || die "bad font spec '$font' (example: '$eg')"
	fi
}

do_gsettings() {
	local schema=$1 key=$2 value=$3 type=${4:-raw}
	if [[ $value == '-' || $value == 'reset' ]]; then
		debug "resetting '$schema' '$key'"
		gsettings reset "$schema" "$key"
		info "$schema $key reset to $(gsettings get "$schema" "$key")"
	elif [[ $value ]]; then
		case ${type#--} in
		    uri)
			value=${value#"'"}
			value=${value%"'"}
			[[ $value == *://* ]] ||
				value="file://$(urlencode -p "$(realpath -s "$value")")"
			value="'$value'"
			;;
		    bool)
			case ${value,,} in
			    t*|y*|1|on)  value="true";;
			    f*|n*|0|off) value="false";;
			esac
			;;
		    string)
			[[ $value == \'*\' ]] ||
				value="'$value'"
			;;
		    relativetime)
			case $value in
			    *m) value=$[ ${value%m} * 60 ];;
			    *h) value=$[ ${value%m} * 60 * 60 ];;
			esac
			value="uint32 $value"
			;;
		esac
		debug "writing '$schema' '$key' '$value'"
		gsettings set "$schema" "$key" "$value"
	else
		debug "reading '$schema' '$key'"
		gsettings get "$schema" "$key"
	fi
}

do_dconf() {
	local path=$1 value=$2
	if [[ $value == '-' || $value == 'reset' ]]; then
		debug "resetting '$path'"
		dconf reset "$path"
	elif [[ $value ]]; then
		debug "writing '$path' \"'$value'\""
		dconf write "$path" "'$value'"
	else
		debug "reading '$path'"
		dconf read "$path"
	fi
}

do_xfconf() {
	local channel=$1 path=$2 value=$3
	if [[ $value == '-' || $value == 'reset' ]]; then
		debug "resetting channel '$channel' path '$path'"
		xfconf-query -c "$channel" -p "$path" --reset
	elif [[ $value ]]; then
		debug "writing channel '$channel' path '$path' to '$value'"
		xfconf-query -c "$channel" -p "$path" --set "$value"
	else
		debug "reading channel '$channel' path '$path'"
		xfconf-query -c "$channel" -p "$path"
	fi
}

setting=$1
value=$2

if [[ $setting == */* ]]; then
	setting=${setting/\//.}
fi

if [[ $setting == *.* ]]; then
	session=${setting%%.*}
	setting=${setting#*.}
else
	session=$DESKTOP_SESSION
	session=${session%-xorg}
fi

case $session.$setting in
*.)
	jq -e -r \
		'to_entries[] | .key as $key | .value | keys[] | "\($key).\(.)"' \
		<<< "$settings" |
		treeify -s. -g -f
	;;
gnome.wallpaper)
	if [[ $value == --fav ]]; then
		cd ~/Pictures/Wallpapers
		value=$(shuf < used.txt | head -1)
		echo "Using $value"
	elif [[ $value == --rand ]]; then
		cd ~/Pictures/Wallpapers
		value=$(find -type f |
			grep -E '\.(jpe?g|png)$' |
			grep -E -v '/Textures/|NSFW|Witty|GNOME-|Old comput' |
			shuf | head -1)
		echo "Using $value"
	elif [[ ! $value ]]; then
		do_gsettings org.gnome.desktop.background picture-uri | sed "s/'//g"
		exit
	fi
	if [[ $value == \'*\' ]]; then
		value=${value#\'}
		value=${value%\'}
	fi
	if [[ $value == file://* ]]; then
		value=${value#'file://'}
		value=$(urlencode -d "$value")
	fi
	if [[ ! -e $value ]]; then
		base=$(basename "$value")
		echo "Trying to find $base"
		new=$(find . -type f -name "$base" | head -n 1)
		if [[ $new && -e $new ]]; then
			echo "Found at $new"
			value=$new
		else
			die "not found: $value"
		fi
	fi
	do_gsettings org.gnome.desktop.background picture-uri "$value" --uri
	;;
*)
	config=$(jq -e \
		--arg session "$session" \
		--arg setting "$setting" \
		'.[$session][$setting]' \
		<<< "$settings")
	if (( $? )); then
		err "unknown setting '$setting'"
		similar=$(jq -e -r \
			'to_entries[] | .key as $key | .value | keys[] | "\($key).\(.)"' \
			<<< "$settings" |
			grep "$(sed 's/./.*&/g' <<< "$setting")")
		if [[ "$similar" ]]; then
			info "similar settings: $similar"
		fi
		exit 1
	fi
	debug "Setting $session.$setting defined as: $config"
	method=$(jq -e -r '.method' <<< "$config")
	if (( $? )); then
		die "BUG: missing '$session.$setting.method'"
	fi
	case $method in
		gsettings)
			eval "$(jq -e -r \
				'@sh "schema=\(.schema) key=\(.key) type=\(.type)"' \
				<<< "$config")"
			do_gsettings "$schema" "$key" "$value" --$type
			;;
		xfconf)
			eval "$(jq -e -r \
				'@sh "chan=\(.channel) prop=\(.property) type=\(.type)"' \
				<<< "$config")"
			do_xfconf "$chan" "$prop" "$value" --$type
			;;
		*)
			die "BUG: unknown method '$method'"
			;;
	esac
	;;
esac
