#!/bin/sh
# Helper functions for packaging and installing OpenRA

####
# This file must stay /bin/sh and POSIX compliant for macOS and BSD portability.
# Copy-paste the entire script into http://shellcheck.net to check.
####

# Compile and publish the core engine and specified mod assemblies to the target directory
# Arguments:
#   SRC_PATH: Path to the root OpenRA directory
#   DEST_PATH: Path to the root of the install destination (will be created if necessary)
#   TARGETPLATFORM: Platform type (win-x86, win-x64, osx-x64, osx-arm64, linux-x64, linux-arm64, unix-generic)
#   RUNTIME: Runtime type (net6, mono)
#   COPY_GENERIC_LAUNCHER: If set to True the OpenRA.exe will also be copied (True, False)
#   COPY_CNC_DLL: If set to True the OpenRA.Mods.Cnc.dll will also be copied (True, False)
#   COPY_D2K_DLL: If set to True the OpenRA.Mods.D2k.dll will also be copied (True, False)
# Used by:
#   Makefile (install target for local installs and downstream packaging)
#   Windows packaging
#   macOS packaging
#   Linux AppImage packaging
#   Mod SDK Windows packaging
#   Mod SDK macOS packaging
#   Mod SDK Linux AppImage packaging
install_assemblies() (
	set -o errexit || exit $?

	SRC_PATH="${1}"
	DEST_PATH="${2}"
	TARGETPLATFORM="${3}"
	RUNTIME="${4}"
	COPY_GENERIC_LAUNCHER="${5}"
	COPY_CNC_DLL="${6}"
	COPY_D2K_DLL="${7}"

	ORIG_PWD=$(pwd)
	cd "${SRC_PATH}"

	if [ "${RUNTIME}" = "mono" ]; then
		echo "Building assemblies"
		rm -rf "${SRC_PATH}/OpenRA."*/obj || :
		rm -rf "${SRC_PATH:?}/bin" || :

		msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}"
		if [ "${TARGETPLATFORM}" = "unix-generic" ]; then
			./configure-system-libraries.sh
		fi

		if [ "${COPY_GENERIC_LAUNCHER}" != "True" ]; then
			rm "${SRC_PATH}/bin/OpenRA.dll"
		fi

		if [ "${COPY_CNC_DLL}" != "True" ]; then
			rm "${SRC_PATH}/bin/OpenRA.Mods.Cnc.dll"
		fi

		if [ "${COPY_D2K_DLL}" != "True" ]; then
			rm "${SRC_PATH}/bin/OpenRA.Mods.D2k.dll"
		fi

		cd "${ORIG_PWD}"

		echo "Installing engine to ${DEST_PATH}"
		install -d "${DEST_PATH}"

		for LIB in "${SRC_PATH}/bin/"*.dll "${SRC_PATH}/bin/"*.dll.config; do
			install -m644 "${LIB}" "${DEST_PATH}"
		done

		if [ "${TARGETPLATFORM}" = "linux-x64" ] || [ "${TARGETPLATFORM}" = "linux-arm64" ]; then
			for LIB in "${SRC_PATH}/bin/"*.so; do
				install -m755 "${LIB}" "${DEST_PATH}"
			done
		fi

		if [ "${TARGETPLATFORM}" = "osx-x64" ] || [ "${TARGETPLATFORM}" = "osx-arm64" ]; then
			for LIB in "${SRC_PATH}/bin/"*.dylib; do
				install -m755 "${LIB}" "${DEST_PATH}"
			done
		fi
	else
		dotnet publish -c Release -p:TargetPlatform="${TARGETPLATFORM}" -p:CopyGenericLauncher="${COPY_GENERIC_LAUNCHER}" -p:CopyCncDll="${COPY_CNC_DLL}" -p:CopyD2kDll="${COPY_D2K_DLL}" -r "${TARGETPLATFORM}" -p:PublishDir="${DEST_PATH}" --self-contained true
	fi
	cd "${ORIG_PWD}"
)

# Copy the core engine and specified mod data to the target directory
# Arguments:
#   SRC_PATH: Path to the root OpenRA directory
#   DEST_PATH: Path to the root of the install destination (will be created if necessary)
#   MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra)
# Used by:
#   Makefile (install target for local installs and downstream packaging)
#   Linux AppImage packaging
#   macOS packaging
#   Windows packaging
#   Mod SDK Linux AppImage packaging
#   Mod SDK macOS packaging
#   Mod SDK Windows packaging
install_data() (
	set -o errexit || exit $?

	SRC_PATH="${1}"
	DEST_PATH="${2}"
	shift 2

	"${SRC_PATH}"/fetch-geoip.sh

	echo "Installing engine files to ${DEST_PATH}"
	for FILE in VERSION AUTHORS COPYING IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP "global mix database.dat"; do
		install -m644 "${SRC_PATH}/${FILE}" "${DEST_PATH}"
	done

	cp -r "${SRC_PATH}/glsl" "${DEST_PATH}"

	echo "Installing common mod files to ${DEST_PATH}"
	install -d "${DEST_PATH}/mods"
	cp -r "${SRC_PATH}/mods/common" "${DEST_PATH}/mods/"

	while [ -n "${1}" ]; do
		MOD_ID="${1}"
		if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then
			echo "Installing mod ${MOD_ID} to ${DEST_PATH}"
			cp -r "${SRC_PATH}/mods/${MOD_ID}" "${DEST_PATH}/mods/"
			cp -r "${SRC_PATH}/mods/modcontent" "${DEST_PATH}/mods/"
		fi

		shift
	done
)

# Compile and publish (using Mono) a windows launcher with the specified mod details to the target directory
# Arguments:
#   SRC_PATH: Path to the root OpenRA directory
#   DEST_PATH: Path to the root of the install destination (will be created if necessary)
#   TARGETPLATFORM: Platform type (win-x86, win-x64)
#   MOD_ID: Mod id to launch (e.g. "ra")
#   LAUNCHER_NAME: Filename (without the .exe extension) for the launcher
#   MOD_NAME: Human-readable mod name to show in the crash dialog (e.g. "Red Alert")
#   ICON_PATH: Path to a windows .ico file
#   FAQ_URL: URL to load when the "View FAQ" button is pressed in the crash dialog (e.g. https://wiki.openra.net/FAQ)
# Used by:
#   Windows packaging
#   Mod SDK Windows packaging
install_windows_launcher() (
	set -o errexit || exit $?

	SRC_PATH="${1}"
	DEST_PATH="${2}"
	TARGETPLATFORM="${3}"
	MOD_ID="${4}"
	LAUNCHER_NAME="${5}"
	MOD_NAME="${6}"
	FAQ_URL="${7}"
	VERSION="${8}"

	rm -rf "${SRC_PATH}/OpenRA.WindowsLauncher/obj" || :

	# See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish for details.
	# Unfortunately there doesn't seem to be a way to set FileDescription and it uses the value of -p:LauncherName.
	# -p:Product sets the "Product name" field.
	# -p:InformationalVersion seems to set the "Product version" field.
	# -p:DisplayName doesn't seem to have a visible effect?
	dotnet publish "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -c Release -r "${TARGETPLATFORM}" -p:LauncherName="${LAUNCHER_NAME}",TargetPlatform="${TARGETPLATFORM}",ModID="${MOD_ID}",PublishDir="${DEST_PATH}",FaqUrl="${FAQ_URL}",InformationalVersion="${VERSION}" --self-contained true

	# NET 6 is unable to customize the application host for windows when compiling from Linux,
	# so we must patch the properties we need in the PE header.
	# Setting the application icon requires an external tool, so is left to the calling code
	python3 "${SRC_PATH}/packaging/windows/fixlauncher.py" "${DEST_PATH}/${LAUNCHER_NAME}.exe"
)

# Write a version string to the engine VERSION file
# Arguments:
#   VERSION: OpenRA version string
#   DEST_PATH: Path to the root of the install destination
# Used by:
#   Makefile (install target for local installs and downstream packaging)
#   Linux AppImage packaging
#   macOS packaging
#   Windows packaging
#   Mod SDK Linux AppImage packaging
#   Mod SDK macOS packaging
#   Mod SDK Windows packaging
set_engine_version() (
	set -o errexit || exit $?

	VERSION="${1}"
	DEST_PATH="${2}"
	echo "${VERSION}" > "${DEST_PATH}/VERSION"
)

# Write a version string to a list of specified mod.yamls
# Arguments:
#   VERSION: OpenRA version string
#   MOD_YAML_PATH [MOD_YAML_PATH...]: One or more mod.yaml files to update
# Used by:
#   Makefile (install target for local installs and downstream packaging)
#   Linux AppImage packaging
#   macOS packaging
#   Windows packaging
#   Mod SDK Linux AppImage packaging
#   Mod SDK macOS packaging
#   Mod SDK Windows packaging
set_mod_version() (
	set -o errexit || exit $?

	VERSION="${1}"
	shift
	while [ -n "${1}" ]; do
		MOD_YAML_PATH="${1}"
		awk -v v="${VERSION}" '{sub("Version:.*$", "Version: " v); print $0}' "${MOD_YAML_PATH}" > "${MOD_YAML_PATH}.tmp"
		awk -v v="${VERSION}" '{sub("/[^/]*: User$", "/"v ": User"); print $0}' "${MOD_YAML_PATH}.tmp" > "${MOD_YAML_PATH}"
		rm "${MOD_YAML_PATH}.tmp"
		shift
	done
)

# Copy launch wrappers, application icons, desktop, and MIME files to the target directory
# Arguments:
#   SRC_PATH: Path to the root OpenRA directory
#   BUILD_PATH: Path to packaging filesystem root (e.g. /tmp/openra-build/ or "" for a local install)
#   OPENRA_PATH: Path to the OpenRA installation (e.g. /usr/local/lib/openra)
#   BIN_PATH: Path to install wrapper scripts (e.g. /usr/local/bin)
#   SHARE_PATH: Parent path to the icons and applications directory (e.g. /usr/local/share)
#   VERSION: OpenRA version string
#   MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra)
# Used by:
#   Makefile (install-linux-shortcuts target for local installs and downstream packaging)
install_linux_shortcuts() (
	set -o errexit || exit $?

	SRC_PATH="${1}"
	BUILD_PATH="${2}"
	OPENRA_PATH="${3}"
	BIN_PATH="${4}"
	SHARE_PATH="${5}"
	VERSION="${6}"
	shift 6

	while [ -n "${1}" ]; do
		MOD_ID="${1}"
		if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then
			if [ "${MOD_ID}" = "cnc" ]; then
				MOD_NAME="Tiberian Dawn"
			fi

			if [ "${MOD_ID}" = "d2k" ]; then
				MOD_NAME="Dune 2000"
			fi

			if [ "${MOD_ID}" = "ra" ]; then
				MOD_NAME="Red Alert"
			fi

			# wrapper scripts
			install -d "${BUILD_PATH}/${BIN_PATH}"
			sed -e 's/{DEBUG}/--debug/' -e "s|{GAME_INSTALL_DIR}|${OPENRA_PATH}|" -e "s|{BIN_DIR}|${BIN_PATH}|" -e "s/{MODID}/${MOD_ID}/g" -e "s/{TAG}/${VERSION}/g" -e "s/{MODNAME}/${MOD_NAME}/g" "${SRC_PATH}/packaging/linux/openra.in" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}"
			sed -e 's/{DEBUG}/--debug/' -e "s|{GAME_INSTALL_DIR}|${OPENRA_PATH}|" -e "s/{MODID}/${MOD_ID}/g" "${SRC_PATH}/packaging/linux/openra-server.in" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server"
			install -m755 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}" "${BUILD_PATH}/${BIN_PATH}"
			install -m755 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server" "${BUILD_PATH}/${BIN_PATH}"
			rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}" "${SRC_PATH}/packaging/linux/openra-${MOD_ID}-server"

			# desktop files
			install -d "${BUILD_PATH}${SHARE_PATH}/applications"
			sed -e "s/{MODID}/${MOD_ID}/g" -e "s/{MODNAME}/${MOD_NAME}/g" -e "s/{TAG}/${VERSION}/g" "${SRC_PATH}/packaging/linux/openra.desktop.in" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop"
			install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop" "${BUILD_PATH}${SHARE_PATH}/applications"
			rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.desktop"

			# icons
			for SIZE in 16x16 32x32 48x48 64x64 128x128; do
				install -d "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/${SIZE}/apps"
				install -m644 "${SRC_PATH}/packaging/artwork/${MOD_ID}_${SIZE}.png" "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/${SIZE}/apps/openra-${MOD_ID}.png"
			done

			if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ]; then
				install -d "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/scalable/apps"
				install -m644 "${SRC_PATH}/packaging/artwork/${MOD_ID}_scalable.svg" "${BUILD_PATH}${SHARE_PATH}/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg"
			fi

			# MIME info
			install -d "${BUILD_PATH}${SHARE_PATH}/mime/packages"
			sed -e "s/{MODID}/${MOD_ID}/g" -e "s/{TAG}/${VERSION}/g" "${SRC_PATH}/packaging/linux/openra-mimeinfo.xml.in" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml"
			install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml" "${BUILD_PATH}${SHARE_PATH}/mime/packages/openra-${MOD_ID}.xml"
			rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.xml"
		fi

		shift
	done
)

# Copy AppStream metadata to the target directory
# Arguments:
#   SRC_PATH: Path to the root OpenRA directory
#   BUILD_PATH: Path to packaging filesystem root (e.g. /tmp/openra-build/ or "" for a local install)
#   SHARE_PATH: Parent path to the appdata directory (e.g. /usr/local/share)
#   MOD [MOD...]: One or more mod ids to copy (cnc, d2k, ra)
# Used by:
#   Makefile (install-linux-appdata target for local installs and downstream packaging)
install_linux_appdata() (
	set -o errexit || exit $?

	SRC_PATH="${1}"
	BUILD_PATH="${2}"
	SHARE_PATH="${3}"
	shift 3
	while [ -n "${1}" ]; do
		MOD_ID="${1}"
		SCREENSHOT_CNC=
		SCREENSHOT_D2K=
		SCREENSHOT_RA=
		if [ "${MOD_ID}" = "ra" ] || [ "${MOD_ID}" = "cnc" ] || [ "${MOD_ID}" = "d2k" ]; then
			if [ "${MOD_ID}" = "cnc" ]; then
				MOD_NAME="Tiberian Dawn"
				SCREENSHOT_CNC=" type=\"default\""
			fi

			if [ "${MOD_ID}" = "d2k" ]; then
				MOD_NAME="Dune 2000"
				SCREENSHOT_D2K=" type=\"default\""
			fi

			if [ "${MOD_ID}" = "ra" ]; then
				MOD_NAME="Red Alert"
				SCREENSHOT_RA=" type=\"default\""
			fi
		fi

		install -d "${BUILD_PATH}${SHARE_PATH}/metainfo"

		sed -e "s/{MODID}/${MOD_ID}/g" -e "s/{MOD_NAME}/${MOD_NAME}/g" -e "s/{SCREENSHOT_RA}/${SCREENSHOT_RA}/g" -e "s/{SCREENSHOT_CNC}/${SCREENSHOT_CNC}/g" -e "s/{SCREENSHOT_D2K}/${SCREENSHOT_D2K}/g" "${SRC_PATH}/packaging/linux/openra.metainfo.xml.in" > "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml"
		install -m644 "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml" "${BUILD_PATH}${SHARE_PATH}/metainfo"
		rm "${SRC_PATH}/packaging/linux/openra-${MOD_ID}.metainfo.xml"

		shift
	done
)
