#!/usr/bin/env bash
#----------------------------------------------------------------------
#
# TODO:
#   - split this into two "actions":
#   	- system
#   	- user 
#   		- create -- start from zero
#   		- init -- if everything is in place but on a clean system, fot
#   		  example when moving a home dir to a clean os install.
#	- keyd -- copy config from syncthing...
#	- tor (user) + link cfg
#	- link config files
#	- copy config files
#	- edit system config files
#	- might be a good idea to add gui/no-gui options...
#	- ssh-keygen...
#	- add --system and --user flags to only do system/user stuff...
#	- profile packager/extractor???
#
# XXX we should split this into user/system config
# XXX might be a good idea to add scripts for more high-level things like:
# 		setup system 
# 			-> setup account 
# 			-> sync config 
# 			-> config specific stuff
# XXX Q: should we do this based on feature or as it is now???
#	A: looks like it would be logical to split this in two:
#		- general system state and singular tools
#		- tasks -- each can consist of configuration and several packages...
# XXX Q: would packing the config files be a good idea??
#
#
#
#----------------------------------------------------------------------
# options...


#FEATURE_DIR=
#DRY_RUN=
#QUIET=




# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

CMD=$(basename $0)

SYSTEM_RC=${0}rc
USER_RC=~/.${CMD}rc

# XXX do we need to split user and system scripts???
SCRIPT_DIR=${0}.d/
USER_SCRIPT_DIR=${0}.d/user/

# System info...
function systemInfo(){
	if ! [ -z "$(type -t dmidecode )" ] ; then
		# XXX should we be more specific here and include model number??
		PLATFORM=$( sudo dmidecode \
			| grep -A3 '^System Information' \
			| grep 'Version:' \
			| sed 's/\s*Version:\s*//' )
	elif ! [ -z "$(type -t uname )" ] ; then
		PLATFORM=$(uname -o)
	else
		PLATFORM=unknown
	fi

	PLATFORM_SCRIPT_DIR=${SCRIPT_DIR}/platform/${PLATFORM}
}



#----------------------------------------------------------------------
# configuration....

# see: ALL_FEATURES below...
FEATURES=(
	dir

	dnf-config
	rpmfusion
	flathub

	dnf
	dnf-remove
	flatpak
	npm
	vim

	tlp
	start-services
	start-user-services

	bashctrl
	syncthing

	# these can depend on some services like syncthing...
	#user-link
	#user-copy

	scripts
	platform-scripts
	user-scripts
)




# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

DIR=(
	~/.bashrc.d
	~/bin
	~/.config
	~/.local/share

	~/Sync/ALL
	~/work/EXTERNAL
)

# NOTE: $DIR and these are not run in order -- linking may need other 
#		stuff done before...
# XXX
CFG_USER_SOURCE=~/Sync/CONFIG/Linux/
CFG_USER_LINK=(
	.gitconfig
	.vimrc .gvimrc .vim
	.tmux.conf
	.config/mc
	.config/ulauncher
)
CFG_USER_COPY=(
) 

PKG_DNF_LATEX=(
	texlive-latex
	texlive-photobook
	texlive-collection-fontsrecommended
	mf
)

# general user env tools...
# XXX add way to alias names for differen platforms...
PKG_CLI_TOOLS=(
	bash
	tmux

	nnn mc tree ncdu 
	zip zstd unrar

	wget rsync lftp

	vim micro
	git
	nodejs golang

	ffmpeg
	exiftool exiv2 vips-tools
)

PKG_DNF=( 
	# system...
	cronie 

	# graphics...
	# install, run vainfo and install the missing driver, e.g. intel-media-driver
	#
	# XXX behaves in an odd way, not sure about this yet...
	#
	# also see: 
	# 	https://github.com/intel/media-driver#known-issues-and-limitations for codec support
	libva libva-utils gstreamer1-vaapi 
	libavcodec-freeworld

	# for intel onboard graphics...
	# 	https://discussion.fedoraproject.org/t/intel-graphics-best-practices-and-settings-for-hardware-acceleration/69944
	# 	https://rpmfusion.org/Howto/Multimedia
	# test if needed:
	# 	$ vainfo
	#intel-media-driver  intel-gpu-tools mesa-dri-drivers mpv

	# also see: https://github.com/AdnanHodzic/auto-cpufreq
	acpi
	smartmontools
	nut

	# tools and recovery...
	gparted gdisk 
	testdisk
	foremost binwalk #scalpel 

	# networking...
	nmap
	syncthing
	tor obfs4 nyx
	yt-dlp qbittorrent httrack

	# tools...
	# XXX prune with $PKG_CLI_TOOLS...
	openssl gpm  
	mc vifm nnn tmux bat tree
	aspell
	rsync rclone
	p7zip zip unrar zstd
	btop htop atop nvtop iftop iotop #csysdig??
	perf
	#wavemon
	ncdu cpu-x glances #stacer
	jdupes fdupes
	keepassxc
	kitty #ghostty
	nextcloud-client
	# XXX not sure if this supports Wayland...
	#flameshot

	# spreasheet editors (cli)
	sc-im visidata
	pandoc

	# fonts...
	mscore-fonts-all
	# tty fonts...
	#	/etc/vconsole.conf
	#		FONT="ter-v24n"
	#	/etc/defaults/grub -- kernel options, add: vconsole.font=...
	#		GRUB_TERMINAL_OUTPUT="gfxterm"
	#		# $ sudo grub2-mkfont \
	#		#		--output=/boot/efi/EFI/fedora/fonts/ter-u32n.pf2 \
	#		#		/usr/share/fonts/terminus-fonts/ter-u32n.otb
	#		GRUB_FONT="/boot/efi/EFI/fedora/fonts/ter-u32n.pf2"
	#		# XXX this sees to have no effect until /etc/vconsole.conf is 
	#		# 		loaded...
	#		GRUB_CMDLINE_LINUX="... vconsole.font=ter-v24n"
	#	rebuild config:
	#		grub2-mkconfig -o /boot/grub2/grub.cfg
	# XXX should we also add a feature to set these up???
	terminus-fonts
	terminus-fonts-console
	terminus-fonts-grub2

	# dev...
	git git-gui
	nodejs golang
	upx

	# media...
	pavucontrol
	vlc mpv cmus mpg123 id3v2 mpd mpc
	ffmpeg
	mkvtoolnix-gui
	avidemux
	exiftool exiv2 vips-tools
	perl-Image-ExifTool
	graphviz

	# codecs...
	gstreamer1-plugin-openh264
	gstreamer1-plugins-bad-free
	gstreamer1-plugins-bad-freeworld
	gstreamer1-plugins-base
	gstreamer1-plugins-good
	gstreamer1-plugins-good-gtk
	gstreamer1-plugins-good-qt
	gstreamer1-plugins-ugly
	gstreamer1-plugins-ugly-free

	# desktop...
	ulauncher 
	gnome-tweaks 
	
	gnome-firmware

	# apps...
	krita
	pdftk
	rawtherapee
	#obs-studio obs-studio-plugin-pwvideo
	# XXX needed for OBS' virtual camera + requires rpmfusion
	#		$ sudo dnf install \
	#			https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
	#		$ sudo dnf install \
	#			https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
	# v4l2loopback

	# Gnome shell extensions...
	gnome-shell-extension-gsconnect
	gnome-shell-extension-caffeine
	gnome-shell-extension-dash-to-panel
	gnome-shell-extension-blur-my-shell
	gnome-shell-extension-appindicator
	gnome-shell-extension-just-perfection

	${PKG_CLI_TOOLS[@]}

	
	${PKG_DNF_LATEX[@]}
)
PKG_DNF_REMOVE=(
	gnome-tour
	gnome-shell-extension-background-logo
	gnome-shell-extension-apps-menu
)


# XXX
PKG_TERMUX=(
	# XXX

	${PKG_CLI_TOOLS[@]}
)

PKG_NPM=(
	tldr 
)

PKG_FLATPAK=(
	# system...
	com.github.tchx84.Flatseal 
	com.mattjakeman.ExtensionManager 
	io.github.gaheldev.Millisecond
	ca.desrt.dconf-editor
	io.github.realmazharhussain.GdmSettings
	org.gustavoperedo.FontDownloader

	# net...
	#org.briarproject.Briar
	io.github.ungoogled_software.ungoogled_chromium
	app.zen_browser.zen
	org.localsend.localsend_app
	io.github.martchus.syncthingtray

	# media...
	fr.handbrake.ghb
	fr.handbrake.ghb.Plugin.IntelMediaSDK
	org.avidemux.Avidemux

	# tools...
	com.logseq.Logseq
	com.github.xournalpp.xournalpp
	ch.openboard.OpenBoard
	org.inkscape.Inkscape
	org.blender.Blender
	org.gimp.GIMP
	#com.rawtherapee.RawTherapee
	#io.github.CyberTimon.RapidRAW
	org.freecad.FreeCAD
	com.usebottles.bottles
)

PKG_SNAP=(
	irfanview
	foobar2000
	snap-store 
)

PKG_GO=(
	github.com/charmbracelet/gum@latest
)


SERVICES_START=(
	crond sshd gpm
)

SERVICES_USER_START=(
)



# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

SAVE=(
	FEATURES
	DIR
	PKG_DNF PKG_FLATPAK PKG_NPM PKG_SNAP
	SERVICES_START SERVICES_USER_START
	CFG_USER_SOURCE CFG_USER_LINK CFG_USER_COPY
)



#----------------------------------------------------------------------
# Builtin features...

ALL_FEATURES=($( \
	cat $0 \
		| grep '^function feature-' \
		| sed 's/function feature-\([^(]*\)(.*$/\1/' \
		| sort))


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# For more info see:
# 	https://fedoramagazine.org/hibernation-in-fedora-36-workstation/
function feature-hibernate(){
	# dracut configuration...
	cat <<-EOF | sudo tee /etc/dracut.conf.d/resume.conf
add_dracutmodules+=" resume "
EOF
	@ dracut -f
	# a service to disable zram before we hibernate...
	# XXX do we need to enable the swap here too???
	cat <<-EOF | sudo tee /etc/systemd/system/hibernate-preparation.service
[Unit]
Description=Disable zram before hibernate
Before=systemd-hibernate.service

[Service]
User=root
Type=oneshot
ExecStart=/usr/sbin/swapoff /dev/zram0

[Install]
WantedBy=systemd-hibernate.service
EOF
	@ sudo systemctl enable hibernate-preparation.service

	# disable some memory checks...
	mkdir -p /etc/systemd/system/systemd-logind.service.d/
	cat <<-EOF | sudo tee /etc/systemd/system/systemd-logind.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF
	@ sudo mkdir -p /etc/systemd/system/systemd-hibernate.service.d/
	cat <<-EOF | sudo tee /etc/systemd/system/systemd-hibernate.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# NOTE: if using exclude=... first remove the package and then add it 
# 		to exclude=...
function feature-dnf-config(){
	if [ -z "$(grep 'f_lynx/post-install' /etc/dnf/dnf.conf)" ] ; then
		echo Updating config
		# a bit ugly...
		cat <<-EOF | sudo tee -a /etc/dnf/dnf.conf > /dev/null

# added by f_lynx/post-install script...
fastmirror=True
max_parallel_downloads=10
defaultyes=True
EOF
	else
		echo Already updated.
	fi
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-dir(){
	@setupList mkdir -p - ${DIR[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# link user files/dirs (syncthing, ...)...
##function feature-user-link(){
##	# XXX
##	true
##}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# copy user files/dirs (syncthing, ...)...
##function feature-user-copy(){
##	# XXX
##	true
##}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-dnf(){
	@ sudo dnf update ${DNF_ARGS}
	@setupList sudo dnf install ${DNF_ARGS} - ${PKG_DNF[@]}
}
function feature-dnf-remove(){
	@setupList sudo dnf remove ${DNF_ARGS} - ${PKG_DNF_REMOVE[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-npm(){
	@setupList sudo npm install -g - ${PKG_NPM[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-rpmfusion(){
	@ sudo dnf install \
		https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
	@ sudo dnf install \
		https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-flathub(){
	@ sudo flatpak remote-add --if-not-exists flathub \
		https://flathub.org/repo/flathub.flatpakrepo
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-flatpak(){
	@setupList sudo flatpak install - ${PKG_FLATPAK[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-snap(){
	@ sudo dnf install snapd
	@ sudo ln -s /var/lib/snapd/snap /snap
	# this is here to compensate for snap not being ready right away...
	# ...did not dig into why...
	@ sleep 5
	@setupList sudo snap install - ${PKG_SNAP[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-go(){
	@ sudo dnf install golang
	@setupList sudo go install - ${PKG_GO[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-start-services(){
	@setupList sudo systemctl start - ${SERVICES_START[@]}
	@setupList sudo systemctl enable - ${SERVICES_START[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-start-user-services(){
	@setupList sudo systemctl --user enable - ${SERVICES_USER_START[@]}
	@setupList sudo systemctl --user start - ${SERVICES_USER_START[@]}
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-tlp(){
	@ sudo dnf install tlp tlp-rdw
	@ sudo dnf remove tuned tuned-ppd
	@ sudo systemctl enable tlp
	@ sudo tlp start
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-vim(){
	@ sudo dnf install vim gvim
	# default editor...
	@ sudo dnf install vim-default-editor --allowerasing
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# see:
# 	https://github.com/rvaiya/keyd
# XXX copy config: /etc/keyd/<keyboard-id>.conf...
function feature-keyd-source(){ (
	@ mkdir -p ~/work/EXTERNAL
	@ cd ~/work/EXTERNAL
	if ! [ -d keyd ] ; then
		@ git clone https://github.com/rvaiya/keyd
	fi
	@ cd keyd
	@ make \
		&& @ sudo make install
	@ sudo systemctl enable keyd \
		&& @ sudo systemctl start keyd

) }
function feature-keyd(){ (
	@ sudo dnf copr enable alternateved/keyd
	@ sudo dnf install keyd
) }
# see: https://wayland.freedesktop.org/libinput/doc/latest/palm-detection.html
function feature-keyd-quirk(){ (
	local QUIRKS_FILE=/etc/libinput/local-overrides.quirks
	# check if already installed...
	if [ -e "$QUIRKS_FILE" ] \
			&& grep -q '\[keyd\]' "$QUIRKS_FILE" ; then
		echo "File \"$QUIRKS_FILE\" already exists and contains \"[keyd]\" section, aborting." 1>&2 
		return
	fi
	# install...
	@ sudo mkdir -p "$(dirname "$QUIRKS_FILE")"
	cat <<-EOF | sudo tee -a "$QUIRKS_FILE" > /dev/null
[keyd]
MatchUdevType=keyboard
MatchName=keyd virtual keyboard
AttrKeyboardIntegration=internal
EOF
) }


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# to update:
# 	$ cd /opt/ventoy && ./VentoyGUI.x86_64
#
# see:
# 	https://copr.fedorainfracloud.org/coprs/karlisk/ventoy/
function feature-ventoy(){ (
	@ sudo dnf copr enable karlisk/ventoy
	@ sudo dnf install ventoy
) }


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# see: 
# 	https://gitlab.com/warningnonpotablewater/libinput-config
# 	https://www.reddit.com/r/Fedora/comments/qn0o9w/adjust_touchpad_scroll_speed_enable_mouse_wheel/ 
function feature-libinput-config(){ (
	@ sudo dnf install libinput libinput-devel systemd-devel
	@ mkdir -p ~/work/EXTERNAL
	@ cd ~/work/EXTERNAL
	if ! [ -d libinput-config ] ; then
		@ git clone https://gitlab.com/warningnonpotablewater/libinput-config.git
	fi
	@ cd libinput-config
	@ meson build
	@ cd build
	@ ninja
	@ sudo ninja install

	# config...
	# for more info on options see: 
	#   https://gitlab.com/warningnonpotablewater/libinput-config
	cat <<-EOF | sudo tee -a /etc/libinput.conf > /dev/null
dwt=enabled
scroll-factor=0.3
gesture-speed=1.5
EOF

) }


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-bashctrl(){ (
	@ mkdir -p ~/work/
	@ cd ~/work/
	if ! [ -d bashctrl ] ; then
		@ git clone git@github.com:flynx/bashctrl
	fi
	@ cd bashctrl
	@ ./bashctrl -y setup
) }


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-gamma(){
	@ mkdir -p ~/work/EXTERNAL/
	@ cd ~/work/EXTERNAL/
	if ! [ -d bashctrl ] ; then
		@ git clone https://github.com/zb3/gnome-gamma-tool
	fi
	@ cd gnome-gamma-tool/
	@ ./gnome-gamma-tool.py -g 1.15
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-far(){
	@ sudo dnf copr enable polter/far2l	
	@ sudo dnf install far2l far2l-tty
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# a disk usage utility...
function feature-dust(){
	@ sudo dnf copr enable gourlaysama/dust
	@ sudo dnf install dust
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-shadowsocks-rust(){
	@ sudo dnf copr enable spyophobia/shadowsocks-rust
	@ sudo dnf install shadowsocks-rust
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-gnome(){
	# fractional scaling...
	#@ gsettings set org.gnome.mutter experimental-features "['scale-monitor-framebuffer']"

	# disable beeps...
	@ gsettings set org.gnome.desktop.sound event-sounds false
	# visual bell...
	@ gsettings set org.gnome.desktop.wm.preferences visual-bell true
	@ gsettings set org.gnome.desktop.wm.preferences visual-bell-type frame-flash

	# per window input selection...
	@ gsettings set org.gnome.desktop.input-sources.per-window true

	# swap language with alt-shift...
	# NOTE: with the way the gui is setup not this is not possible to set there...
	@ gsettings set org.gnome.desktop.wm.keybindings switch-input-source-backward "['<Alt>Shift_L']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-input-source "['<Shift>Alt_L']"

	# Workspaces...
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-1 "['<Super>Home', '<Super>F1']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-2 "['<Super>F2']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-3 "['<Super>F3']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-4 "['<Super>F4']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-5 "['<Super>F5']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-6 "['<Super>F6']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-7 "['<Super>F7']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-last "['<Super>End']"

	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Super>Page_Up', '<Super><Alt>Left', '<Control><Alt>Left']"
	@ gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right "['<Super>Page_Down', '<Super><Alt>Right', '<Control><Alt>Right']"

	# XXX
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function feature-syncthing(){
	@ mkdir -p ~/Sync/ALL
	@ sudo dnf install syncthing
	@ sudo systemctl --user enable --now syncthing 
	#@ sudo systemctl --user start syncthing 
	# XXX can we do this from CLI???
	#		need to:
	#			- link device
	#			- share ALL directory
	#			- wait for sync
	echo "Waiting for Syncthing to be connected with other devices manually."
	read -p "(press any key when done)"
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX needs a bit more setup...
function feature-snapshots(){ (
	@ dnf install snapper python3-dnf-plugin-snapper
	@ sudo snapper -c root create-config /
	@ sudo snapper -c home create-config /home
	#@ sudo snapper -c boot create-config /boot

	@ cd ~/work/EXTERNAL/
	if ! [ -d grub-btrfs ] ; then
		@ git clone https://github.com/Antynea/grub-btrfs.git
	fi
	@ cd grub-btrfs
	@ sudo make install
) }


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX needs a bit more setup...
function feature-s1yoga-touchpad(){
	
	# XXX detect hardware and abort setup on non-compatible machines...

	cat <<EOF | sudo tee /usr/lib/systemd/system-sleep/fix-touchpad
#!/bin/sh

# fixes an issue where the touchpad stops working after suspend/hibernate... 
if [ "$${1}" == "post" ] ; then
	modprobe -r i2c_i801
	sleep 3
	modprobe i2c_i801
fi
EOF

	@ chmod +x /usr/lib/systemd/system-sleep/fix-touchpad
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX are these the same thing???
#		- suspend does not work...
#		- hibernate works on the second try only...
function feature-s1yoga-syspend(){
	# XXX did not figure this one out yet...
	true
}
function feature-s1yoga-hibernate(){
	# XXX did not figure this one out yet...
	# XXX HACK (will this work?)
	#		if hibernate fails retry once
	#		if second try fails beep
	true 
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# XXX skip scripts starting in "-" 
# XXX make the scripts support the same syntax as features...
function feature-scripts(){ (
	if ! [ -z "$1" ] ; then
		local dir=$1
	else
		local dir=$SCRIPT_DIR
	fi

	# no script dir...
	[ -d "$dir" ] \
		|| return 1

	cd "$dir"l
	local script
	for script in * ; do
		# skip README and scripts starting with '-'...
		( [ "${script}" == "README" ] \
				|| [ "${script:0:1}" == "-" ] )\
			&& continue
		echo "# $script:"
		( @ ./$script )
	done
) }

function feature-platform-scripts(){
	systemInfo
	feature-scripts "$PLATFORM_SCRIPT_DIR"
}

function feature-user-scripts(){
	feature-scripts "$USER_SCRIPT_DIR"
}




#----------------------------------------------------------------------
# feature api...

function @feature(){
	while ! [ -z "$1" ] ; do
		local feauture="$1"
		for f in "${FEATURES[@]}" ; do
			if [ "$f" == "${feature}" ] ; then
				return 0
			fi
		done
		shift
	done
	false
}

function @feature-add(){
	while ! [ -z "$1" ] ; do
		if ! @feature "$1" ; then
			FEATURES+=("$1")
		fi
		shift
	done
}

function @feature-del(){
	while ! [ -z $1 ] ; do
		FEATURES=( ${FEATURES[@]/$1} )
		shift
	done
}


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# XXX add an interactive list editor???
# XXX


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# command runners...


# Print command and if $DRY_RUN is not set run it...
#
function @(){
	# XXX this does not preserve quotes...
	[ -z $QUIET ] \
		&& echo "## $@"
	if [ -z $DRY_RUN ] ; then 
		$@

	# need to exit with true status on dry runs...
	else
		true
	fi
}

# Setup list if not empty...
#
# Usage:
#	@setupList CMD - LIST
#
function @setupList(){
	local CMD=
	local LST=
	# get command...
	while true ; do
		if [ $# == 0 ] || [ $1 == "-" ]  ; then
			shift
			break
		fi
		CMD="$CMD $1"
		shift
	done
	# list...
	LST=("$@")

	# run command if list is not empty...
	if [ ${#LST[@]} != 0 ] ; then
		@ $CMD ${LST[@]}
	fi
}


#----------------------------------------------------------------------
# config...

[ -e "${SYSTEM_RC}" ] \
	&& source ${SYSTEM_RC}

[ -e "${USER_RC}" ] \
	&& source ${USER_RC}



#----------------------------------------------------------------------
# help and arguments...

function listScripts(){
	[ -d "$SCRIPT_DIR" ] \
		&& echo "-" \
		&& return 0

	local scripts=( $(ls "$SCRIPT_DIR") )
	echo ${scripts/README}
}

function printhelp(){ cat << EOF
Usage: $CMD [OPTIONS]

Options:
    -h | --help             - print this message and exit.
    -d | --dry-run          - report the actions but do nothing.
    -q | --quiet            - run in quiet mode.

    -l | --list-features    - list enabled features.
    -la | --list-all-features 
                            - list supported features.
    -ls | --list-scripts    - list available scripts.

External configuration:
    -s | --source FILE      - read config from file.
                              (this flag can be used multiple times)
    -o | --output FILE      - write config to file.

Feature list manipulation:
    -all                    - clear features
    +all                    - reset features to \$ALL_FEATURES
    -FEATURE                - remove FEATURE from list
    +FEATURE                - add FEATURE to lost

Helpers:
    --make-platform-dir     - make platform directory for current platform
                              and exit.
                              Location: 
                                  ${SCRIPT_DIR}/platform/NAME


Default features:
  ${FEATURES[@]}

Supported features:
  ${ALL_FEATURES[@]}

Available scripts:
  $( listScripts )


Examples:
    Only create dirs and links (features dir and user-link)...
    \$ $CMD -all +dir +user-link

    Same as above...
    \$ FEATURES=( dir user-link )  $CMD

EOF
}

while ! [ -z "$1" ] ; do
	case "$1" in
		-h|--help)
			printhelp
			exit
			;;
		-d|--dry-run)
			DRY_RUN=1
			shift
			;;
		-q|--quiet)
			QUIET=1
			shift
			;;

		# introspection...
		-l|--list-features)
			echo ${FEATURES[@]}
			exit
			;;
		-la|--list-all-features)
			echo ${ALL_FEATURES[@]}
			exit
			;;
		-ls|--list-scripts)
			listScripts
			exit
			;;

		# config files...
		-s|--source)
			[ -z "$2" ] \
				&& source "$2"
			shift
			shift
			;;
		-o|--output)
			SAVE=1
			SAVE_FILE=$2
			shift
			shift
			;;

		# helpers...
		--make-platform-dir)
			systemInfo
			echo "# Patform script dir: $PLATFORM_SCRIPT_DIR"
			[ -d "$PLATFORM_SCRIPT_DIR" ] \
				|| @ mkdir -p "$PLATFORM_SCRIPT_DIR"
			exit
			;;


		# feature manipulation...
		# NOTE: keep these last...
		+all)
			FEATURES=( ${ALL_FEATURES[@]} )
			shift
			;;
		-all)
			FEATURES=()
			shift
			;;
		+*)
			@feature-add "${1:1}"
			shift
			;;
		-*)
			@feature-del "${1:1}"
			shift
			;;
	esac
done





#----------------------------------------------------------------------
# install/setup stuff...

echo "# FEATURES: ${FEATURES[@]}"

# built-in functions...
# NOTE: order of execution is set by $ALL_FEATURES...
_features=( "${FEATURES[@]}" )
for feature in "${ALL_FEATURES[@]}" ; do
	# skip...
	@feature "$feature" \
		|| continue

	# functions...
	if [ "$(type -t feature-$feature)" == "function" ] ; then
		echo "# $feature:"
		_features=( ${_features[@]/$feature} )
		feature-$feature
	fi
done
# features not in $ALL_FEATURES...
for feature in "${_features[@]}" ; do
	echo "# $feature:"
	# built-in...
	if [ "$(type -t feature-$feature)" == "function" ] ; then
		feature-$feature

	# feature scripts...
	elif [ -d "$FEATURE_DIR" ] ; then
		"$FEATURE_DIR"/$feature

	# err...
	else
		echo "$CMD: unknown feature: $feature"
	fi
done


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# save...

# XXX






#----------------------------------------------------------------------
# vim:set ts=4 sw=4 nowrap :
