#!/bin/bash

shopt -s nocasematch

INPUTFILE="$1"
OUTPUTFILE="$2"

# application/x-ms-shortcut (.lnk) support, thanks to jopka (https://launchpad.net/~jopka)
if [[ ${INPUTFILE##*.} = 'lnk' ]]
then
	which winepath >&2 || exit

	INPUTFILE="$(
		winepath -u "$(winedump "$INPUTFILE" \
		| sed -n -r '/^LocalPath of/s/.*\("(.*\.[Ee][Xx][Ee])"\)$/\1/p')"
	)"

	[ ! "$INPUTFILE" ] && exit
	SHORTCUT='TRUE'

fi

TEMPFILE1=$(mktemp)
TEMPFILE2=$(mktemp)
TEMPTHUMB=$(mktemp)

# Get the current icon theme (or override it by 4th parameter):
eval THEME="${4:-$(gsettings get org.gnome.desktop.interface icon-theme)}"
#THEME="${THEME:-$(gconftool-2 --get /desktop/gnome/interface/icon_theme)}"

# Delete previously created thumbnails if icon theme has been changed since last run
if [ -d $HOME/.cache/thumbnails ] 
then
	THUMBNAILS_PATH=$HOME/.cache/thumbnails

else
	THUMBNAILS_PATH=$HOME/.thumbnails

fi

if [ ! "$THEME" = "$(cat $THUMBNAILS_PATH/gnome-exe-thumbnailer.cfg)" ]
then
	rm $(cat $THUMBNAILS_PATH/gnome-exe-thumbnailer.files)
	> $THUMBNAILS_PATH/gnome-exe-thumbnailer.files
	echo "$THEME" > $THUMBNAILS_PATH/gnome-exe-thumbnailer.cfg

fi

echo "$THUMBNAILS_PATH/*/$(echo -n "$3" | md5sum | cut -d' ' -f1).png" \
>> "$THUMBNAILS_PATH/gnome-exe-thumbnailer.files"

case "$THEME" in
	Faience*)
		THEME='faience'
		DRAW='roundRectangle 2,2 45,45 3,3'
		SHADOW='+1'
	;;

	elementary*|Ubuntu-Mono*|Humanity*)
		THEME='elementary'
		DRAW='roundRectangle 2,2 45,45 3,3'
		SHADOW='+1'
	;;

	Faenza*)
		THEME='faenza'
		DRAW='roundRectangle 2,2 45,45 3,3'
		SHADOW='+1'
	;;

	elementary*|Ubuntu-Mono*|Humanity*)
		THEME='elementary'
		DRAW='roundRectangle 2,2 45,45 3,3'
		SHADOW='+1'
	;;

	AwOken)
		THEME='awoken'
		DRAW='roundRectangle 3,3 44,44 3,3'
		SHADOW='-1'
	;;

	AwOkenWhite)
		THEME='awoken-white'
		DRAW='roundRectangle 3,3 44,44 3,3'
		SHADOW='-1'
	;;

	AwOkenDark)
		THEME='awoken-dark'
		DRAW='roundRectangle 4,4 43,43 3,3'
		SHADOW='-1'
	;;

	gnome|Human)
		THEME='gnome'
		DRAW='roundRectangle 2,2 45,45 4,4'
		SHADOW='+0'
	;;

	Breathe)
		THEME='breathe'
		DRAW='roundRectangle 1,2 46,45 2,2'
		SHADOW='+1'
	;;

	NITRUX)
		THEME='nitrux'
		DRAW='roundRectangle 2,2 45,45 1,1'
		SHADOW='+0'
	;;

	box)
		THEME='box'
		DRAW='roundRectangle 5,5 42,42 1,1'
		SHADOW='+0'
	;;

	Moka)
		THEME='moka'
		DRAW='roundRectangle 2,2 45,45 11,11'
		SHADOW='+0'
	;;

	Tango*|*)
		THEME='tango'
		DRAW='roundRectangle 2,2 45,45 4,4'
		SHADOW='+1'
	;;

esac


if [[ ${INPUTFILE##*.} = 'msi' ]]
then
	# Use generic installer icon for a .msi package:
	ICON=/usr/share/pixmaps/gnome-exe-thumbnailer/$THEME/installer.png
	TUNE='-modulate 120,100,0'

else
	# Extract group_icon resource. If we get the "wrestool: $INPUTFILE could not find `1' in
	# `group_icon' resource." error, there is a 99.9% chance that input file is an installer.

	# Warning: Some redirection magic ahead.

	if wrestool --extract --type=group_icon "$INPUTFILE" 2>&1 >$TEMPFILE1 \
	| grep "could not find \`1' in \`group_icon' resource"
	then
		# Use generic installer icon:
		ICON=/usr/share/pixmaps/gnome-exe-thumbnailer/$THEME/installer.png
		TUNE='-modulate 120'

	else
		# Process extracted data, if we have some:
		if [ -s $TEMPFILE1 ]
		then
			# Look for the best usable icon. 32x32x32 is the first choice, but sometimes is that icon only
			# an empty box with no visible pixels (e.g. in Simon Tatham's Portable Puzzle Collection).
			# In that case we can try to lower the bit depth and look again.
			for BITDEPTH in 32 24 8 4 1
			do
				read OFFSET INDEX < <(
					icotool --list $TEMPFILE1 | awk '{
						ci=int(substr($2,index($2,"=") + 1));
						cw=int(substr($3,index($3,"=") + 1));
						cb=int(substr($5,index($5,"=") + 1));

						if (((cw > w && cw <= 32) || (cw == w && cb > b)) && cb <= '$BITDEPTH') {
							b = cb;
							w = cw;
							i = ci;
						}
					}
					END {
						print (32 - w) / 2, i;
					}'
				)

				# Use a resized 48x48 icon if 32x32 or smaller isn't available.
				# This is very rare (e.g. peazip.exe), but it happens sometimes:
				if [ "$INDEX" = '' ]
				then
					INDEX=1
					RESIZE=yes
					OFFSET=$(($OFFSET - 16))
				fi

				# Finally try to extract chosen icon:
				icotool --extract --index=$INDEX $TEMPFILE1 -o $TEMPFILE2

				if [ -s $TEMPFILE2 ]
				then
					ICON=$TEMPFILE2
					[ "$RESIZE" ] && mogrify -resize 32x32 $ICON

				else
					# This case generally happens when the hi-res icons are in new "Vista" icon format (bunch of compressed PNGs).
					# Icotool from icoutils 0.29.1 supports it already, but is unable to extract the one selected icon only.

					# Try to extract all icons:
					icotool --extract $TEMPFILE1 -o /tmp

					# There's always a 32x32x32 icon in "Vista" icons, but just to be sure:
					[ -s ${TEMPFILE1}_${INDEX}_32x32x${BITDEPTH}.png ] && ICON=${TEMPFILE1}_${INDEX}_32x32x${BITDEPTH}.png

				fi

				if [ "$ICON" ]
				then
					# Verify that the selected icon is not just an empty box:
					if [ "$(convert $ICON -filter box -resize 1x1! -format "%[fx:u]" info:)" = '0' ]
					then
						# Take next iteration with lower bit depth
						unset ICON
						continue

					else
						break

					fi

				else
					break

				fi

			done

		fi

	fi

fi

# Create the basic thumbnail:

if [ "$ICON" ]
then
	# Calculate the backgroud color:
	COLOR=$(
		convert $ICON -background white -flatten -fill white \
		-fuzz 40% -opaque black -level 33%,66% -scale 1x1! $TUNE txt:- \
		| tail -1 \
		| grep -o '#......'
	)

else
	# Just use the generic icon with backgroud color based on md5sum:
	HUE=$(md5sum "$INPUTFILE" | cut -c 1-2)
	HUE=$(printf "%d" 0x$HUE)
	COLOR="hsb($HUE, 50%, 90%)"

	LABEL=${INPUTFILE##*/}
	LABEL=$(sed 's/^./\U&/; s/.$/\L&/' <<< "${LABEL:0:2}")

	# Dim color for non-executable files:
	if [[ ! ${INPUTFILE##*.} = 'exe' ]]
	then
		LIGHT=80
		TUNE_NX='-modulate 100,20'
	fi

	convert -size 48x48 xc:none -gravity center -font Helvetica-Narrow-Bold -pointsize 24 \
	-fill '#0000005C' -annotate $SHADOW+3 "$LABEL" \
	-fill "hsb($HUE, 3%, ${LIGHT:-100}%)" -annotate +0+2 "$LABEL" \
	png:$TEMPFILE1

	ICON=$TEMPFILE1
	OFFSET=-8

fi

# Create the final thumbnail:
OFFSET=$(($OFFSET + 8))

if [ "$SHORTCUT" ]
then
	# Variant with MS shortcut emblem in bottom left corner for .lnk files
	convert -size 48x48 xc:none -fill "$COLOR" -draw "$DRAW" $TUNE_NX miff:- \
	| composite -compose multiply /usr/share/pixmaps/gnome-exe-thumbnailer/$THEME/template.png - miff:- \
	| composite -geometry +$OFFSET+$OFFSET $ICON - png:- \
	| composite -gravity southwest /usr/share/pixmaps/gnome-exe-thumbnailer/shortcut.png - $TEMPTHUMB

else
	# Plain variant
	convert -size 48x48 xc:none -fill "$COLOR" -draw "$DRAW" $TUNE_NX miff:- \
	| composite -compose multiply /usr/share/pixmaps/gnome-exe-thumbnailer/$THEME/template.png - png:- \
	| composite -geometry +$OFFSET+$OFFSET $ICON - $TEMPTHUMB

fi

# Get the version number:
if [[ ${INPUTFILE##*.} = 'msi' ]]
then
	# Look for the ProductVersion property if user has the Microsoft (R) Windows Script Host installed:
	if which wine && grep -v 'Wine placeholder DLL' $HOME/.wine/drive_c/windows/system32/cscript.exe
	then
		# Workaround wine bug #19799: cscript crashes if you call WScript.Arguments(0)
		# http://bugs.winehq.org/show_bug.cgi?id=19799
		<<< "
			Dim WI, DB, View, Record
			Set WI = CreateObject(\"WindowsInstaller.Installer\")
			Set DB = WI.OpenDatabase(\"$INPUTFILE\",0)
			Set View = DB.OpenView(\"SELECT Value FROM Property WHERE Property = 'ProductVersion'\")
			View.Execute
			Wscript.Echo View.Fetch.StringData(1)
		" iconv -f utf8 -t unicode > $TEMPFILE1.vbs

		VERSION=$(
			DISPLAY=NONE wine cscript.exe //E:vbs //NoLogo Z:\\tmp\\${TEMPFILE1##*/}.vbs 2>/dev/null \
			| egrep -o '^[0-9]+\.[0-9]+(\.[0-9][0-9]?)?(beta)?'
		)

	else
		# Try to get the version number from extended file properties at least:
		VERSION=$(
			file "$INPUTFILE" \
			| grep -o ', Subject: .*, Author: ' \
			| egrep -o '[0-9]+\.[0-9]+(\.[0-9][0-9]?)?(beta)?' \
			| head -1
		)
	fi

else
	# Extract raw version resource:
	wrestool --extract --raw --type=version "$INPUTFILE" > $TEMPFILE1

	if [ -s $TEMPFILE1 ]
	then
		# Search for a sane version string.
		# This (especially the final regexp) took me really long time to figure out. Am I that lame?
		VERSION=$(< $TEMPFILE1 \
			tr '\0, ' '\t.\0' \
			| sed 's/\t\t/_/g' \
			| tr -c -d '[:print:]' \
			| sed -r -n 's/.*Version[^0-9]*([0-9]+\.[0-9]+(\.[0-9][0-9]?)?).*/\1/p'
		)
	fi
fi


# Put a version label on the thumbnail:
if [ "$VERSION" ]
then
	convert -font -*-clean-medium-r-*-*-6-*-*-*-*-*-*-* \
	-background transparent -fill white label:"$VERSION" \
	-trim -bordercolor '#00001090' -border 2 \
	-fill '#00001048' \
	-draw $'color 0,0 point\ncolor 0,8 point' -flop \
	-draw $'color 0,0 point\ncolor 0,8 point' -flop \
	miff:- | composite -gravity southeast - $TEMPTHUMB $OUTPUTFILE
else
	cp $TEMPTHUMB $OUTPUTFILE
fi

rm $TEMPFILE1* $TEMPFILE2 $TEMPTHUMB

