#!/bin/bash

# TEMPUS --- Themes Every Meticulous Person Ultimately Seeks (yes, this
# is a backronym).
#
# Handles the integration between my custom desktop session[0] and my
# Tempus themes[1].  TEMPUS performs live theme switching, while also
# updating the relevant configuration files.  The main use case for this
# is as part of BSPWM, but some actions will also work in GNOME or MATE
# (the latter being my fallback DE on Debian).
#
# 0: https://gitlab.com/protesilaos/dotfiles
# 1: https://gitlab.com/protesilaos/tempus-themes (partially
#    incorporated in my dotfiles)
#
# Copyright (c) 2019-2020 Protesilaos Stavrou <info@protesilaos.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.


# Error handling and help messages
# --------------------------------
_help_message() {
	echo "Run this script with a single argument:"

	# The parameter expansions here keep only the theme's unique name:
	# /path/to/tempus_classic.sh ==> classic
	while IFS= read -r -d $'\0' line; do
		line="${line##[a-z/_]*tempus_}"
		printf "\\t%s\\n" "${line%.sh}"
	done < <(find "$HOME"/.local/share/my_colours/shell/ -type f -name '*.sh' -print0 | sort -z)

	echo "This assumes you have used STOW on my 'colours' directory (part of my dotfiles)"
}

[ "$#" -eq 1 ] || { _help_message; exit 1; }

tempus_theme="$1"

# Is the theme light or dark?
#
# TODO 2019-11-17: Themes should expose information about their variant.
# This approach is fragile.  Changes must be implements in the generator:
# https://gitlab.com/protesilaos/tempus-themes-generator
case "$tempus_theme" in
	dawn|day|fugit|past|totus)
		theme_variant=light
		;;
	autumn|classic|dusk|future|night|rift|spring|summer|tempest|warp|winter)
		theme_variant=dark
		;;
	*)
		echo "_$1_ is not a valid Tempus theme."
		_help_message
		;;
esac

# Program-specific functions
# --------------------------

# Shorter version of the sed command we will be using throughout…
_sed() {
	sed --follow-symlinks -i "$@" &
}

_sed_sync() {
	# Here we make an exception for the _sed function, because if we run
	# this asynchronously, other processes might fail to get the new
	# colours.  To my knowledge as of 2019-06-27, this appears to be
	# better than using sleep and/or until…
	sed --follow-symlinks -i "$@"
}

# Check for dependency, else exit the given function that calls this.
_depcheck() {
	command -v "$1" > /dev/null || { echo "Missing dependency: $1."; return 1; }
}

# Debian Buster optional dependencies:
# 	apt install papirus-icon-theme arc-theme
_gtk() {
	_gtk_common() {
		# GTK 2
		_sed "s,\(gtk-theme-name=\).*,\1\'${1}\', ; s,\(gtk-icon-theme-name=\).*,\1\'${2}\'," \
             "$HOME"/.gtkrc-2.0

		# GTK 3
		_sed "s,\(gtk-theme-name=\).*,\1${1}, ; s,\(gtk-icon-theme-name=\).*,\1${2}," \
             "$HOME"/.config/gtk-3.0/settings.ini
	}

	_gtk_variant() {
        local path
        path=/usr/share

        # TODO what if one has one but not the other?
		if [ -d "$path"/themes/"$1" ] && [ -d "$path"/icons/"$2" ]; then
			_gtk_common "$1" "$2"
		else
			_gtk_common Adwaita Adwaita
		fi
	}

	_gtk_live() {
		_depcheck xsettingsd

        local xsettingsd
        xsettingsd="$HOME"/.config/xsettingsd/xsettingsd.conf

        if [ -f "$xsettingsd" ]; then
            _sed "s,\(.*\/ThemeName\) \"[a-zA-Z-]*\",\1 \"${1}\"," "$xsettingsd"
            _sed "s,\(.*\/IconThemeName\) \"[a-zA-Z-]*\",\1 \"${2}\"," "$xsettingsd"
        fi

        # This is a very lightweight program that simply loads the
        # settings it reads from the file.  Kill and run again to read
        # the new values.
        pgrep -xo xsettingsd && pkill -xo xsettingsd
        xsettingsd -c "$xsettingsd"
	}

	case "$theme_variant" in
		l*)
			_gtk_variant 'Arc' 'Papirus-Light' &
			_gtk_live 'Arc' 'Papirus-Light' &
			;;
		d*)
			_gtk_variant 'Arc-Dark' 'Papirus-Dark' &
			_gtk_live 'Arc-Dark' 'Papirus-Dark' &
			;;
	esac
}

_vim() {
	_depcheck vim

	_sed "s,\(colorscheme \).*,\1tempus_${tempus_theme}," "$HOME"/.vimrc
}

_x_and_shell() {
	tempus_files="$HOME/.local/share/my_colours"
	tempus_active_x="$tempus_files/active-tempus-theme.Xcolors"
	tempus_active_sh="$tempus_files/active-tempus-theme.sh"
	tempus_active_content="$tempus_files/active-theme-content"

	_check_tempus() {
		[ -n "$1" ] || { echo "Path for Tempus themes is unavailable."; return 1; }
	}

	_check_tempus "$tempus_files"
	_check_tempus "$tempus_active_x"
	_check_tempus "$tempus_active_sh"

	# IMPORTANT once modified, let other processes use the new colours.
	_sed_sync "s,\(^source.*tempus_\).*,\1${tempus_theme}.sh," "$tempus_active_sh" && source "$tempus_active_sh"

	# Update the X colours, so that new X programs inherit them.
	_sed "s,\(^#include.*tempus_\).*,\1${tempus_theme}.Xcolors\"," "$tempus_active_x"

	# Create a new file as well that is used to get the colour values
	# of the running terminal.
	#
	# This is used by: repaint_terminals
	grep '^.*=' "$tempus_files/shell/tempus_${tempus_theme}.sh" > "$tempus_active_content"

    # Another one of my scripts for live recolouring running terminal
    # emulators, by using escape sequences.
    repaint_terminals &

	# This one is an older script of mine.  In need of review…  MATE
	# Terminal is a fallback option, in case Xterm gives me problems
	# (because MATE is my "plan B" desktop environment).
	own_script_mate_terminal_setup &

	_depcheck xterm

	xresources="$HOME"/.Xresources
	if [ -f "$xresources" ]; then
		xrdb -I "$HOME" -merge "$xresources"
	fi
}

_emacs() {
    _depcheck emacs

    pgrep -x emacs > /dev/null || return 1

    # Just switch to the appropriate Emacs theme.  The Modus themes are
    # not part of Tempus, but their goal is the same.
    #
    # See:
    #
    # 1. https://protesilaos.com/dotemacs
    # 2. https://gitlab.com/protesilaos/modus-themes
    case "$theme_variant" in
        l*) emacsclient -e "(prot/modus-operandi)" ;;
        d*) emacsclient -e "(prot/modus-vivendi)"  ;;
	esac
}

_bspwm() {
    _depcheck bspwm

	pgrep -x bspwm || return 1

	_bc() {
		bspc config "$@"
	}

	_bc normal_border_color "$backgroundalt"
	_bc presel_feedback_color "$backgrounddim"
	if [ "$theme_variant" = 'light' ]; then
		_bc active_border_color "$color1"
		_bc focused_border_color "$color4"
	else
		_bc active_border_color "$color3"
		_bc focused_border_color "$color6"
	fi

	bspwmrc="$HOME/.config/bspwm/bspwmrc"

	[ -x "$bspwmrc" ] || { echo "Missing bspwmrc."; return 1; }

	case "$theme_variant" in
		l*)
			_sed "/^[^#].*active_border_color/ s,#[a-zA-Z0-9]*,$color1, ; \
			/^[^#].*focused_border_color/ s,#[a-zA-Z0-9]*,$color4, ; \
			/^[^#].*normal_border_color/ s,#[a-zA-Z0-9]*,$backgroundalt, ; \
			/^[^#].*presel_feedback_color/ s,#[a-zA-Z0-9]*,$backgrounddim," "$bspwmrc"
			;;
		d*)
			_sed "/^[^#].*active_border_color/ s,#[a-zA-Z0-9]*,$color3, ; \
			/^[^#].*focused_border_color/ s,#[a-zA-Z0-9]*,$color6, ; \
			/^[^#].*normal_border_color/ s,#[a-zA-Z0-9]*,$backgroundalt, ; \
			/^[^#].*presel_feedback_color/ s,#[a-zA-Z0-9]*,$backgrounddim," "$bspwmrc"
			;;
	esac
}

_rofi() {
    _depcheck rofi

    roficonf="$HOME"/.config/rofi/config.rasi
	if [ -f "$roficonf" ]; then
		_sed "s/tempus_[a-z]*/tempus_${tempus_theme}/" "$roficonf"
	fi
}

# Function call cascade
# ---------------------
_x_and_shell
_emacs
_rofi
_gtk
_bspwm
_vim
