#!/usr/bin/env bash
# vim: autoindent noexpandtab
# shellcheck disable=SC2237
set -e
#set -x

# APT but only for fonts
# alex@aiei.ch
# christopher@bocki.com
VERSION=1.9
# Defaults
BASE=${XDG_DATA_HOME:-"$HOME/.local/share"}
TARGET="$BASE/fonts"
FNTDATA="$BASE/fnt"
# Fallback if ~/.local/share doesn't exist as if fnt would be the first program
# writing to it... HAH!
if ! test -d "$BASE"; then
	BASE="$HOME"
	TARGET="$BASE/.fonts"
	FNTDATA="$BASE/.fnt"
fi
FNTINDEXDIR="$FNTDATA/index"
PACKAGES="$FNTDATA/Packages.xz"
APACHE="$FNTDATA/APACHE.xz"
OFL="$FNTDATA/OFL.xz"
MIRROR="https://deb.debian.org/debian"
INDEX="$MIRROR/dists/sid/main/binary-all/Packages.xz"
GINDEX="https://alexmyczko.github.io/fnt"
APACHEINDEX="$GINDEX/APACHE.xz"
OFLINDEX="$GINDEX/OFL.xz"
if [ ! -d "$FNTDATA" ] || [ ! -d "$FNTINDEXDIR" ]; then
	mkdir -p "$FNTINDEXDIR" || { echo "Couldn't create cache+index directory: $FNTDATA + /index" ; exit 1 ; }
fi

if ! command -v uname &>/dev/null; then
	s="Windows"
else
	s=$(uname -s)
fi

check_com() { if ! command -v "$1" &> /dev/null; then return 1; fi ; }

# Pipelines
pipe_download(){
	local PIPEFILE
	PIPEDIR="$(mktemp -d)"
	PIPEFILE="${1%%*/}"
	if test -z "$PIPEFILE"; then PIPEFILE=index; fi
	chmod go-rwx "$PIPEDIR"
	trap 'rm -rf -- "$PIPEDIR"' EXIT
	download "$1" "$PIPEDIR/$PIPEFILE"
	cat "$PIPEDIR/$PIPEFILE"
}

search() {
	if [ -r "$PACKAGES" ] && [ -r "$APACHE" ] && [ -r "$OFL" ]; then
		xzcat "$PACKAGES" | awk '/^Package: fonts-.*'"$1"'.*/ {gsub(/^Package: /,"");print;}'
		xzcat "$APACHE" "$OFL" | awk '/^Package: .*'"$1"'.*/ {gsub(/^/, "google-", $2); print $2}'
	else
		echo "Can't find any Data, please run ${BASH_SOURCE[0]} update and try again."
	fi
}

download() {
	# shellcheck disable=SC2086
	local URL LOPTS
	URL="$1"
	if test -z "${1##*.deb}"; then
		if /usr/bin/which /usr/lib/apt/apt-helper>/dev/null
		then
			# Test if we could use an local apt-proxy (non-ssl) but no worry we do
			# md5sum checking on the file anyway.
			PROXYURL=${URL/https:/http:}
			if test -n "$(/usr/lib/apt/apt-helper auto-detect-proxy "$PROXYURL" |
				awk -F\' '{print $2}')"; then
							URL=$PROXYURL;
			fi
			# shellcheck disable=SC2090,SC2086
			/usr/lib/apt/apt-helper $LOPTS download-file "$URL" "$2" >/dev/null
			return
		fi
	fi
	if /usr/bin/which fetch>/dev/null
	then
		fetch -q -o "$2" "$URL"
	elif /usr/bin/which curl>/dev/null
	then
		curl -g -L -s -o "$2" "$URL"
	elif /usr/bin/which wget>/dev/null
	then
		wget -q -O "$URL" "$2"
	else
		print "ERROR: neither apt-helper, wget, curl nor fetch is installed" >&2
		exit 69
	fi
}

deb_handler() {
	# retrieve font from debian mirror and store infos for removal
	TMPDIR="$(mktemp -d)"
	chmod go-rwx "$TMPDIR"
	trap 'rm -rf -- "$TMPDIR"' EXIT
	PIT="${TMPDIR}/extract"
	mkdir -m go-rwx "$PIT" || { echo "Couldn't eat tartar." ; exit 73 ; }
	NAME="$1"
	INFOS="$(unxz -c "$PACKAGES" | awk "/^Package: ${NAME}$/,/^$/" | awk '/^(Version|Installed-Size|Filename|Size|MD5sum): /')"
	VER="$(awk '/^Version: /{print$2}' <<< "$INFOS")"
	INSTSIZE="$(awk '/^Installed-Size: /{print$2}' <<< "$INFOS")"
	DOWNSIZE="$(awk '/^Size: /{print$2}' <<< "$INFOS")"
	FPATH="$(awk '/^Filename: /{print$2}' <<< "$INFOS")"
	FNAME="$(basename "$FPATH")"
	MD5SUM="$(awk '/^MD5sum: /{print$2}' <<< "$INFOS") ${FNAME}"
	echo "Installing $NAME $VER [${DOWNSIZE} ${INSTSIZE}000 ${MIRROR}/${FPATH}]..."
	cd "$TMPDIR" || { echo "Couldn't cd into $TMPDIR" ; exit 66 ; }
	test -z "$(download "${MIRROR}/${FPATH}" "${TMPDIR}/$FNAME")" || { echo "Couldn't retrieve file." ; exit 69 ; }
	echo "$MD5SUM" > "${TMPDIR}/${FNAME}.md5"
	if $md5 -c "${TMPDIR}/${FNAME}.md5" >/dev/null; then
		# deb data
		DATA="$(ar t "$TMPDIR/$FNAME" | grep '^data\.tar')"
		mkdir -p "${PIT}/data" && cd "${PIT}/data"
		ar x "${TMPDIR}/$FNAME" "$DATA"
		tar xf "${PIT}/data/$DATA"
		find "${PIT}/data" -name "*.?tf" -exec cp {} "$TARGET" \;
		# deb control
		CONTROL="$(ar t "$TMPDIR/$FNAME" | grep '^control\.tar')"
		mkdir -p "${PIT}/control" && cd "${PIT}/control"
		ar x "${TMPDIR}/$FNAME" "$CONTROL"
		tar xf "${PIT}/control/${CONTROL}"
		sed -n 's/^\(.*\) .*\/\(.*tf$\)/\1 \2/p' "${PIT}/control/md5sums" > "$FNTINDEXDIR/$NAME"
		awk -v pkg="$NAME" '{printf "Package: %s File: %s\n", pkg, $2}' "$FNTINDEXDIR/$NAME"
	else
		echo "Can't verify md5sum!"
		exit 65
	fi
}

fnt_install() {
	local a o p
	a='' o='' p=''
	if [ ! -f "$PACKAGES" ]; then
		echo "Could not find $PACKAGES"
		echo "Please run ${BASH_SOURCE[0]} update"
		# could also just run itself with update...
		# but apt doesn't do that either :)
		exit 75
	fi
	if [ ! $# -eq 2 ]; then
		echo "No fontname supplied."
		echo "Usage: ${BASH_SOURCE[0]} install agave"
		exit 64
	fi
	FNTMATCH=$2
	if [ ! -d "$TARGET" ]; then
		mkdir -p "$TARGET"
	fi
	# look for first font match
	p="$(unxz -c "$PACKAGES" | awk '/^Package: (fonts-)?'"$FNTMATCH"'/ {gsub(/^Package: /,"");print;exit;}')"
	if !  [ -z "$p" ]; then
		deb_handler "$p"
		return
	fi
	FNTMATCH=${FNTMATCH/google-/}
	a="$(unxz -c "$APACHE" | awk '/Package: '"$FNTMATCH"'$/,/^$/')"
	if ! [ -z "$a" ]; then
		url=$(awk '/^URL:/ {print$2}' <<< "$a")
		dir="${url##*/}"
		files="$(awk '/^ .*\.?tf$/ {print $2}' <<< "$a")"
		md5sums="$(awk '/^ .*\.?tf$/ {gsub(/^ /,""); print}' <<< "$a")"
		for file in $files; do
			download "${url}/${file}" "${TARGET}/${file}"
			echo "Package: $FNTMATCH File: $file"
		done
		echo "$md5sums" > "${FNTINDEXDIR}/google-${dir}"
		return
	else
		o="$(unxz -c "$OFL" | awk '/Package: '"$FNTMATCH"'$/,/^$/')"
		if ! [ -z "$o" ]; then
			url="$(awk '/^URL:/ {print$2}' <<< "$o")"
			dir="${url##*/}"
			files="$(awk '/^ .*\.?tf$/ {print $2}' <<< "$o")"
			md5sums="$(awk '/^ .*\.?tf$/ {gsub(/^ /,""); print}' <<< "$o")"
			for file in $files; do
				download "${url}/${file}" "${TARGET}/${file}"
				echo "Package: $FNTMATCH File: $file"
			done
			echo "$md5sums" > "${FNTINDEXDIR}/google-${dir}"
			return
		fi
	fi
}

render_preview() {
	PREVIEW="$1"
	_app=(
chafa="-w 9"
timg=""
)
	for a in "${_app[@]}"; do
		bin=${a%=*}
		opt=${a#*=}
		if check_com "$bin"; then
			if file --brief --mime-type "$PREVIEW" |grep -q 'image/*'; then
				# shellcheck disable=SC2086
				$bin $opt "$PREVIEW"
				return 0
			fi
			return 0
		else
			missing=( "${missing[@]}" "$bin" )
		fi
	done
	echo "Warning: ${missing[*]} not available. Please install one of them." >&2
	echo -e "\v\t${PREVIEWURI}\v"
	return 69
}


preview() {
	PREVIEW="${FNTDATA}/preview.png"
	PREVIEWURI="https://screenshots.debian.net/screenshot/fonts-$1"
	if download "$PREVIEWURI" "${PREVIEW}"; then
		# if we get nothing / "this picture is not available" pic
		if [ "$($md5 "$PREVIEW" | awk '{print$1}')" = "b5765b390157e36eaf721c8848a4b04d" ]; then
			PREVIEWURI="$GINDEX/preview/$1/preview.webp"
			if download "$PREVIEWURI" "$PREVIEW"; then
				if ! file --brief --mime-type "$PREVIEW" |grep -q 'image/*'; then
					echo "Couldn't retrieve a preview for ${1}."
					exit 69
				fi
			fi
		fi
		if render_preview "$PREVIEW"; then
			PRINTED=1
			echo "$1: $PREVIEWURI"
		fi
	fi
	if [ "$PRINTED" != "1" ]; then
		echo "Couldn't display a preview for $1." >&2
		return 69
	fi
}

case "$s" in
	Darwin)
		#echo macOS
		md5="md5sum"
		check="$md5 curl brew otfinfo ar"
		# otfinfo comes with lcdf-typetools
		i="brew"
		TARGET="$HOME/Library/Fonts/"
		FNTDATA="$HOME/.fnt"
	;;
	Linux|GNU/kFreeBSD|GNU)
		#echo Linux
		md5="md5sum"
		check="$md5 ar awk curl file otfinfo tar unxz xzcat"
		i="apt"
#		TARGET="$HOME/.fonts/"
		if [ 0 -eq "$(id -u)" ]; then
			TARGET="/usr/local/share/fonts/"
		fi
	;;
	FreeBSD)
		#echo FreeBSD
		md5="md5"
		check="$md5 curl otfinfo ar"
		i="pkg"
		TARGET="$HOME/.fonts"
		FNTDATA="$HOME/.fnt"
	;;
	OpenBSD)
		#echo OpenBSD
		md5="md5"
		check="$md5 curl otfinfo ar"
		i="pkg_add"
		#TARGET="$HOME/.local/share/fonts"
	;;
	Haiku)
		#echo Haiku OS
		check="curl ar"
		i="pkgman"
		TARGET="$HOME/config/non-packaged/data/fonts"
		FNTDATA="$HOME/.fnt"
	;;
	Windows)
		#echo Windows
		check="cmd.exe"
		i="ENOPKGMANAGER"
		TARGET="$USERPROFILE\\Fonts"
	;;
	*)
		echo "Please report $s to https://github.com/alexmyczko/fnt/issues"
		exit 1
	;;
esac

for a in $check; do
	if ! command -v "$a" &>/dev/null; then
		echo "$a not found, please use $i to install it."
		exit 69
	fi
done

cat=$(command -v lolcat || :)
PATH="/usr/games:$PATH"
if test -z "$cat"; then cat=$(command -v cat); fi

case "$1" in
	help|-h)
		cat << 'EOF'
Syntax: fnt [ update | list [indexfile]| info | help ]
        fnt [ install | remove | preview | search ] font

help|-h    this help
info       information about how many fonts can be installed and are available
install|-i install a font
list|-l    lists installed fonts with glyphcount per font
preview|-p preview a font
remove|-r  remove a font
search|-s  search for font
update|-u  updates the font package index of debian sid
EOF
	;;

	update|-u)
		echo -n "Updating... "
		mkdir -p "${FNTDATA}/index" && rm -rf "$PACKAGES" "$APACHE" "$OFL"
		PACKAGESTMP=$(mktemp)
		download "$INDEX" "$PACKAGESTMP"
		xzcat "$PACKAGESTMP" | awk '/^Package: fonts-/,/^$/' > "${PACKAGES%.xz}";
		xz "${PACKAGES%.xz}" ; rm "$PACKAGESTMP" ; echo -n "${PACKAGES##*/}... "
		download "$APACHEINDEX" "$APACHE"; echo -n "${APACHE##*/}... "
		download "$OFLINDEX" "$OFL"; echo -n "${OFL##*/}... "
		echo -n -e "done.\n"
	;;

	info)
		mkdir -p "$FNTINDEXDIR"
		INSTALLEDFONTS=$(fnt list index)
		ALLFONTS=$(${BASH_SOURCE[0]} search)
		printf 'fnt v:%s infos...\nFNTDATA %s (%s)\nTARGET %s (%s)\n' \
			"$VERSION" \
			"$FNTDATA" "$(du -hs "$FNTDATA" 2>/dev/null |cut -f1)" \
			"$TARGET" "$(du -hs "$TARGET" 2>/dev/null |cut -f1)"
		printf 'Available Fonts from\tDebian: %i\tGoogle: %i\n' \
			"$(grep -c '^fonts-' <<< "$ALLFONTS")" \
			"$(grep -c '^google-' <<< "$ALLFONTS")"
		printf 'Installed Fonts from\tDebian: %i\tGoogle: %i\n' \
			"$(grep -c '^fonts-' <<< "$INSTALLEDFONTS")" \
			"$(grep -c '^google-' <<< "$INSTALLEDFONTS")"
	;;

	list|-l)
		if [ $# -eq 1 ]; then
			find "$TARGET" -iname '*.?tf' 2>/dev/null |
				sort | while read -r f; do
					IDX=$(basename "$(grep -rl "$(basename "$f")" "$FNTINDEXDIR")")
					if test -z "$IDX"; then IDX=NOT-MANAGED-BY-FNT; fi
					echo "$IDX: $(basename "${f}") [$(otfinfo -u "$f" 2>/dev/null | wc -l | awk '{print $1}')]"
					unset IDX
				done
		fi
		if [ $# -eq 2 ] && [ "$2" = "index" ] ; then
			find "$FNTINDEXDIR" -type f | awk -F'/' '{print $NF}'
		fi
		if [ $# -eq 2 ] && [ -r "$FNTINDEXDIR/$2" ]; then
			# shellcheck disable=SC2046
			find $(awk -v target="$TARGET" \
				'{printf "%s/%s ", target, $2}' "$FNTINDEXDIR/$2") |
				while read -r font; do
					echo "$(basename "${font}") [$(otfinfo -u "$font" 2>/dev/null | wc -l)]"
				done
		fi
	;;
	preview|-p)
		if [ $# -ne 2 ]; then
			echo "No fontname supplied."
			echo "Usage: ${BASH_SOURCE[0]} preview agave"
			exit 64
		fi
		mkdir -p "$FNTINDEXDIR"
		rm -f "${FNTDATA}/preview.png"
		FNTMATCH="$(sed -E 's/^(fonts|google)-//g' <<< "$2")"
		preview "$FNTMATCH"
	;;
	install|-i)
		fnt_install "$@"
	;;
	remove|-r)
		if [ $# -eq 1 ] ; then
			echo "Usage: ${BASH_SOURCE[0]} remove fonts-agave agave-b-autohinted.ttf"
			echo "To get a list of indexes/files: ${BASH_SOURCE[0]} list [index|fonts-agave]"
		fi
		if [ $# -eq 2 ] && [ -w "$FNTINDEXDIR/$2" ] ; then
			if [ -e "$FNTINDEXDIR/$2" ]; then
			awk '{print$2}' "$FNTINDEXDIR/$2" |while read -r FONTFILE; do
			${BASH_SOURCE[0]} remove "$2" "$FONTFILE"
		done
		else
			echo "Couldn't find the font $2"
			fi
		rm -fv "${FNTINDEXDIR:?}/$2"
		fi
		if [ $# -eq 3 ] && [ -w "$FNTINDEXDIR/$2" ] && [ -w "$TARGET/$3" ] ; then
			if grep -q "$3" "$FNTINDEXDIR/$2"; then
				rm -fv "${TARGET:?}/${3:?}"
			fi
		fi
	;;
	search|-s)
		search "$2"
	;;
	purge)
		if [ $# -eq 1 ] ; then
			echo "This command will remove $TARGET and $FNTDATA!"
			echo -e "If you are certain use:\n\t${BASH_SOURCE[0]} purge yes-i-am-sure"
			echo "You have been warned."
		fi
		if [ $# -eq 2 ] && [ "$2" = "yes-i-am-sure" ] ; then
			rm -Rvf "${TARGET:?}" "${FNTDATA:?}"
		fi
	;;
	moo)
		echo "This fnt does not have cow powers."
	;;
	wak)
		$cat << 'EOF'
  _()< wak wak
 (__)
EOF
	;;
	quak)
		$cat << 'EOF'
 _______
< QUAK? >
 -------
     \
      \
          oO)-.                       .-(Oo
         /__  _\                     /_  __\
         \  \(  |     ()~()         |  )/  /
          \__|\ |    (-___-)        | /|__/
          '  '--'    ==`-'==        '--'  '
EOF
	;;
	*)
		$cat << EOF
   .d888   $VERSION
  d88P"           888
  888             888
.d88888 888888b. d888888
  888   888 "88b  888
  888   888  888  888
  888   888  888  Y88b.
  888   888  888   "Y888
EOF
	;;
esac
