#!/bin/bash

# This script is designed to integrate AppImage applications into the system.
# This script is free software distributed without any warranty. You can use
# modify and redistribute it under the terms of the CeCILL licence (GPL compatible).
# Licence: [CeCILL](https://cecill.info/licences/Licence_CeCILL_V2.1-en.txt)
# Author: Frank ENDRES <first@last.fr>
# Date: 2025-12-10
# Version: 0.2

set -euo pipefail #strict mode


#Constants
readonly PARAM_ERROR=1
readonly MOUNT_ERROR=11
readonly MISSING_DESKTOP_ERROR=12
readonly REMOVE_ERROR=13


function print_usage() {
	echo "usage: $0 install path/to/file.AppImage" >&2
	echo "usage: $0 list" >&2
	echo "usage: $0 remove cmd" >&2
	exit $PARAM_ERROR
}

if (( $# < 1 )); then
	print_usage
fi


if [ "$(id -u)" == "0" ]; then #as root
	readonly APPIMAGE_PATH=/usr/local/share/AppImages
	readonly BIN_PATH=/usr/local/bin
	readonly DESKTOP_PATH=/usr/local/share/applications
	readonly ICON_PATH=/usr/local/share/icons
else
	readonly APPIMAGE_PATH=$HOME/.local/AppImages
	readonly BIN_PATH=$HOME/.local/bin
	readonly DESKTOP_PATH=$HOME/.local/share/applications
	readonly ICON_PATH=$HOME/.local/share/icons
fi
mkdir -p $APPIMAGE_PATH $BIN_PATH $DESKTOP_PATH $ICON_PATH


function install_app() {
	local appimage=$1
	local pid

	chmod +x $appimage #mount AppImage
	local tmp_file=$(mktemp)
	local cmd=$appimage
	if [[ ${cmd:0:1} != '/' ]]; then cmd="./$cmd"; fi
	$cmd --appimage-mount > $tmp_file & #background process bypass strict mode
	local pid=$!
	local mount_point=''
	while [ -d /proc/$pid ] && ([ -z "$mount_point" ] || [ ! -d $mount_point ]); do
		sleep 1; mount_point=$(cat $tmp_file)
	done
	rm -f $tmp_file
	if [ -z "$mount_point" ]; then
		echo "error: could not mount $appimage" >&2
		exit $MOUNT_ERROR
	fi

	#install desktop file and icon
	desktop_file=$(ls $mount_point/*.desktop 2>/dev/null | head -n1 || true)
	if [ -z "$desktop_file" ]; then
		echo "error: missing desktop file" >&2
		kill $pid
		exit $MISSING_DESKTOP_ERROR
	fi
	local exec_path=$(cat $desktop_file | grep Exec | head -n1 | cut -f2 -d= | cut -f1 -d' ')
	local exec=$(basename $exec_path)
	#~ local exec=$(basename $(cat $desktop_file | grep Exec | head -n1 | cut -f2 -d= | cut -f1 -d' '))
	cp $desktop_file $DESKTOP_PATH/$exec.desktop
	sed "s@Exec=$exec_path@Exec=$BIN_PATH/$exec@" -i $DESKTOP_PATH/$exec.desktop
	local icon=$(ls $mount_point/*.svg $mount_point/*.png 2>/dev/null | head -n1 || true)
	if [ ! -z "$icon" ]; then
		local ext=$(echo $icon | rev | cut -f1 -d. | rev)
		cp $icon $ICON_PATH/$exec.$ext
		desktop-file-edit --set-icon=$exec $DESKTOP_PATH/$exec.desktop
	fi

	kill $pid #umounts AppImage

	if [ -L $BIN_PATH/$exec ] && [ "$(dirname $(readlink -f $BIN_PATH/$exec))" == "$APPIMAGE_PATH" ] ; then
		rm -f $(readlink -f $BIN_PATH/$exec)
	fi

	mv $appimage $APPIMAGE_PATH/ #install AppImage
	ln -sf $APPIMAGE_PATH/$(basename $appimage) $BIN_PATH/$exec
}


if [ "$1" == "install" ] && (( $# >= 2 )); then
	appimage=$2
	if [ ! -f $appimage ]; then
		echo "error: $app does not exist"
		exit $MISSING_APPIMAGE_ERROR
	fi
	install_app $appimage

elif [ "$1" == "list" ]; then
	for exec in $(ls $BIN_PATH/); do
		if [ -L $BIN_PATH/$exec ] && [ "$(dirname $(readlink -f $BIN_PATH/$exec))" == "$APPIMAGE_PATH" ] ; then
			if grep -q "X-AppImage-Version" $DESKTOP_PATH/$exec.desktop; then
				version=$(cat $DESKTOP_PATH/$exec.desktop | grep "X-AppImage-Version" | cut -f2 -d= | sed 's/\.[^0-9].*$//')
			else
				for version in $(readlink -f $BIN_PATH/$exec | sed -e 's/-/ /g' -e 's/_/ /g'); do
					if echo $version | grep -q "^v\?[0-9\.]\+\(\.AppImage\)\?$"; then
						version=$(echo $version | sed -e 's/^v//' -e 's/\.AppImage$//')
						break
					else
						version=""
					fi
				done
			fi
			if [ -z "$version" ]; then echo "$exec"; else echo "$exec ($version)"; fi
		fi
	done

elif [ "$1" == "remove" ] && (( $# == 2 )); then
	exec=$2
	if [ -L $BIN_PATH/$exec ] && [ "$(dirname $(readlink -f $BIN_PATH/$exec))" == "$APPIMAGE_PATH" ] ; then
		rm -f $BIN_PATH/$exec $DESKTOP_PATH/$exec.desktop $ICON_PATH/$exec.* $(readlink -f $BIN_PATH/$exec)
	else
		echo "error: $BIN_PATH/$exec doesn't exist or link to $APPIMAGE_PATH/" >&2
		exit $REMOVE_ERROR
	fi

else
	print_usage
fi
