#!/usr/bin/env sh

# Obtain location of source root.
src_root () {
	local SCRIPT_LOCATION=""
	local SYSTEM=$(uname -s)
	if [ ! "x${SYSTEM}" = "xDarwin" ]; then
		local SCRIPT=$(readlink -f "$0")
		SCRIPT_LOCATION=$(dirname $(readlink -f "$0"))
	else
		SCRIPT_LOCATION=$(cd "$(dirname "$0")"; pwd)
	fi

	echo $(cd "$(dirname "${SCRIPT_LOCATION}")"; pwd)
}

SRC_ROOT=$(src_root)

if [ "x${GETOPT}" = "x" ]; then
	GETOPT="getopt"
fi

MAKE_OPTS="-j 4"

USAGE="Usage:\n\t$0 [options]\n\n"
USAGE="${USAGE}Supported options:\n"
USAGE="${USAGE}\t-h, --help\n\t\tPrints help message.\n"
USAGE="${USAGE}\t-p\n\t\tAlso build packages and installers.\n"
USAGE="${USAGE}\t-P\n\t\tDon't compile, just build the packages and installers. This implies -p.\n"
USAGE="${USAGE}\t-v, --version <version>\n\t\tExplicitly specify package version.\n"
USAGE="${USAGE}\t--shared (default)\n\t\tCompile with shared libraries.\n"
USAGE="${USAGE}\t--i386 (default)\n\t\tCompile for the i386 architecture.\n"
USAGE="${USAGE}\t--x86_64\n\t\tCompile for the x86_64 architecture.\n"
USAGE="${USAGE}\t--debug\n\t\tCompile in debug mode.\n"
USAGE="${USAGE}\t--release (default)\n\t\tCompile in release mode.\n"
USAGE="${USAGE}\t--home-dir-data (default)\n\t\tCompile default (i.e. installation) variant.\n"
USAGE="${USAGE}\t--portable-data\n\t\tCompile portable variant.\n"

cd "${SRC_ROOT}"

COMPILE_SRC="yes"
BUILD_PACKAGES="no"

VERSION=""

BUILD_TYPE=""
BUILD_SHARED="shared"
BUILD_STATIC="static"

ARCH_NAME=""
ARCH_I386="i386"
ARCH_X86_64="x86_64"
DFLT_ARCH_NAME="${ARCH_I386}"

MODE=""
MODE_DEBUG="debug"
MODE_RELEASE="release"

VARIANT=""
VARIANT_HOME_DIR="home-dir-data"
VARIANT_PORTABLE="portable-data"

if ! "${GETOPT}" -l test: -u -o t: -- --test test > /dev/null; then
	echo "The default getopt does not support long options." >&2
	echo "You may provide such getopt version via the GETOPT variable e.g.:" >&2
	echo "GETOPT=/opt/local/bin/getopt $0" >&2
	exit 1
fi

# Parse rest of command line
set -- $("${GETOPT}" -l help -l version: -l shared -l i386 -l x86_64 -l debug -l release -l home-dir-data -l portable-data -u -o hpPv: -- "$@")
if [ $# -lt 1 ]; then
	echo -e ${USAGE} >&2
	exit 1
fi

while [ $# -gt 0 ]; do
	OPTION="$1"
	PARAM="$2"
	case "${OPTION}" in
	-h|--help)
		echo -e ${USAGE}
		exit 0
		;;
	-p)
		if [ "x${BUILD_PACKAGES}" = "xno" ]; then
			BUILD_PACKAGES="yes"
		else
			echo "Option -d already set." >&2
			exit 1
		fi
		;;
	-P)
		if [ "x${COMPILE_SRC}" = "xyes" ]; then
			COMPILE_SRC="no"
			BUILD_PACKAGES="yes"
		else
			echo "Option -P already set." >&2
			exit 1
		fi
		;;
	-v|--version)
		if [ "x${VERSION}" = "x" ]; then
			VERSION="${PARAM}"
		else
			echo "Version already set." >&2
		fi
		shift
		;;
	--shared)
		if [ "x${BUILD_TYPE}" = "x" ]; then
			BUILD_TYPE="${BUILD_SHARED}"
		else
			echo "Build type already specified or in conflict." >&2
			exit 1
		fi
		;;
	--i386)
		if [ "x${ARCH_NAME}" = "x" ]; then
			ARCH_NAME="${ARCH_I386}"
		else
			echo "Architecture already specified or in conflict." >&2
			exit 1
		fi
		;;
	--x86_64)
		if [ "x${ARCH_NAME}" = "x" ]; then
			ARCH_NAME="${ARCH_X86_64}"
		else
			echo "Architecture already specified or in conflict." >&2
			exit 1
		fi
		;;
	--debug)
		if [ "x${MODE}" = "x" ]; then
			MODE="${MODE_DEBUG}"
		else
			echo "Build mode already specified or in conflict." >&2
			exit 1
		fi
		;;
	--release)
		if [ "x${MODE}" = "x" ]; then
			MODE="${MODE_RELEASE}"
		else
			echo "Build mode already specified or in conflict." >&2
			exit 1
		fi
		;;
	--home-dir-data)
		if [ "x${VARIANT}" = "x" ]; then
			VARIANT="${VARIANT_HOME_DIR}"
		else
			echo "Variant already specified or in conflict." >&2
			exit 1
		fi
		;;
	--portable-data)
		if [ "x${VARIANT}" = "x" ]; then
			VARIANT="${VARIANT_PORTABLE}"
		else
			echo "Variant already specified or in conflict." >&2
			exit 1
		fi
		;;
	--)
		shift
		break
		;;
	-*|*)
		echo "Unknown option '${OPTION}'." >&2
		echo -e ${USAGE} >&2
		exit 1
		;;
	esac
	unset OPTION
	unset PARAM
	shift
done
if [ $# -gt 0 ]; then
	echo -e "Unknown options: $@" >&2
	echo -en ${USAGE} >&2
	exit 1
fi

# Use shared libraries by default.
if [ "x${BUILD_TYPE}" = "x" ]; then
	BUILD_TYPE="${BUILD_SHARED}"
fi

# Use i386 by default.
if [ "x${ARCH_NAME}" = "x" ]; then
	ARCH_NAME="${ARCH_I386}"
fi

# Use release by default.
if [ "x${MODE}" = "x" ]; then
	MODE="${MODE_RELEASE}"
fi

# Use data in home directory by default.
if [ "x${VARIANT}" = "x" ]; then
	VARIANT="${VARIANT_HOME_DIR}"
fi

BUILD_ROOT="${SRC_ROOT}"

APP_NAME="datovka"

PROJECT_FILE="${APP_NAME}.pro"

CLI_APP_NAME="datovka-cli"
CLI_PROJECT_FILE="${CLI_APP_NAME}.pro.noauto"

QMAKE_PORTABLE_OPT=""
if [ "x${VARIANT}" = "x${VARIANT_PORTABLE}" ]; then
	APP_NAME="${APP_NAME}-portable"
	CLI_APP_NAME="${CLI_APP_NAME}-portable"
	QMAKE_PORTABLE_OPT="PORTABLE_APPLICATION=1"
fi

# Simple Windows path to POSIX path conversion.
win_to_posix_path () {
	echo "/$1" | sed -e 's/\\/\//g' -e 's/://g'
}

LIBS_DIR="shared_built"

# Prefer compilers from QT_TOOLS_Wxy location. Check compiler target.
if [ "x${ARCH_NAME}" = "x${ARCH_I386}" ]; then
	if [ "x${QT_W32}" != "x" ]; then
		export PATH=$(win_to_posix_path ${QT_W32}):${PATH}
	else
		echo "The variable QT_W32 appears to be non-existent or empty." >&2
		echo "Set it to the location of the 32-bit Qt tools, e.g. c:\\Qt\\5.15.1\\mingw81_32\\bin." >&2
	fi
	if [ "x${QT_TOOLS_W32}" != "x" ]; then
		export PATH=$(win_to_posix_path ${QT_TOOLS_W32}):${PATH}
	else
		echo "The variable QT_TOOLS_W32 appears to be non-existent or empty." >&2
		echo "Set it to the location of the 32-bit Qt tools, e.g. c:\\Qt\\Tools\\mingw810_32\\bin." >&2
	fi

	if [ $(g++ -dumpmachine) != "i686-w64-mingw32" ]; then
		echo "Unexpected compiler target machine. Was expecting 'i686-w64-mingw32'." >&2
		exit 1
	fi

	LIBS_DIR="shared_built_i386"
elif [ "x${ARCH_NAME}" = "x${ARCH_X86_64}" ]; then
	if [ "x${QT_W64}" != "x" ]; then
		export PATH=$(win_to_posix_path ${QT_W64}):${PATH}
	else
		echo "The variable QT_W64 appears to be non-existent or empty." >&2
		echo "Set it to the location of the 64-bit Qt tools, e.g. c:\\Qt\\5.15.1\\mingw81_64\\bin." >&2
	fi
	if [ "x${QT_TOOLS_W64}" != "x" ]; then
		export PATH=$(win_to_posix_path ${QT_TOOLS_W64}):${PATH}
	else
		echo "The variable QT_TOOLS_W64 appears to be non-existent or empty." >&2
		echo "Set it to the location of the 64-bit Qt tools, e.g. c:\\Qt\\Tools\\mingw810_64\\bin." >&2
	fi

	if [ $(g++ -dumpmachine) != "x86_64-w64-mingw32" ]; then
		echo "Unexpected compiler target machine. Was expecting 'x86_64-w64-mingw32'." >&2
		exit 1
	fi

	LIBS_DIR="shared_built_x86_64"
else
	echo "Unknown architecture." >&2
	exit 1
fi

LIBS_PATH="libs/${LIBS_DIR}"

APP_DIR="${APP_NAME}.${ARCH_NAME}.built"

# Extract sources if compiling a specific version.
if [ "x${VERSION}" != "x" ]; then
	SRC_FILE="datovka-${VERSION}.tar.xz"
	if [ ! -f "${SRC_FILE}" ]; then
		echo "File '${SRC_FILE}' is missing." >&2
		exit 1
	fi
	tar -xJf "${SRC_FILE}"
	unset SRC_FILE

	APP_DIR="${APP_DIR}.${VERSION}"
	BUILD_ROOT="${SRC_ROOT}/datovka-${VERSION}"

	mkdir -p "${BUILD_ROOT}/${LIBS_PATH}"
	cp -a "${SRC_ROOT}/${LIBS_PATH}/bin" "${BUILD_ROOT}/${LIBS_PATH}/"
	cp -a "${SRC_ROOT}/${LIBS_PATH}/include" "${BUILD_ROOT}/${LIBS_PATH}/"
fi

PKG_VER=$(cat ${BUILD_ROOT}/pri/version.pri | grep '^VERSION\ =\ ' | sed -e 's/VERSION\ =\ //g')

BUNDLING_WARNING=""

if [ "x${COMPILE_SRC}" = "xyes" ]; then
	QMAKE="qmake.exe"
	LRELEASE="lrelease.exe"
	WINDEPLOYQT="windeployqt.exe"
	MAKE="mingw32-make.exe"
	USE_EAY32=""

	# Test command presence.
	for CMD in "${LRELEASE}" "${QMAKE}"; do
		LOCATION=$(which "${CMD}")
		if [ "x${LOCATION}" = "x" ]; then
			echo "Cannot find executable '${CMD}'." >&2
			exit 1
		fi

		unset LOCATION
	done

	# Test the presence of build libraries.
	if [ ! -d "${SRC_ROOT}/$LIBS_PATH" ]; then
		echo "Directory '${SRC_ROOT}/$LIBS_PATH' does not exist." >&2
		exit 1
	fi

	STATIC="0"
	if [ "x${BUILD_TYPE}" = "x${BUILD_STATIC}" ]; then
		STATIC="1"
		echo "This script does not support static builds." >&2
		exit 1
	fi

	pushd "${BUILD_ROOT}"

	rm -rf debug release

	USE_EAY32=$(${QMAKE} pri/test_eay32.pro 2>&1 | grep "eay32")
	if [ "x${USE_EAY32}" != "x" ]; then
		USE_EAY32="--use-eay32"
	fi

	PARAM_MODE=$(${QMAKE} pri/test_windeployqt.pro 2>&1 | grep "provide")
	if [ "x${PARAM_MODE}" != "x" ]; then
		PARAM_MODE="-m ${MODE}"
	fi

	${LRELEASE} "${PROJECT_FILE}"
	DEBUG_INFO_OPT=""
	#if [ "x${BUILD_TYPE}" = "x${BUILD_SHARED}" ]; then
	#	# https://stackoverflow.com/a/35704181
	#	DEBUG_INFO_OPT="CONFIG+=force_debug_info"
	#fi
	echo ${QMAKE} CONFIG+="${MODE}" WITH_BUILT_LIBS=1 STATIC="${STATIC}" ${QMAKE_PORTABLE_OPT} ${DEBUG_INFO_OPT} "${PROJECT_FILE}" -r -spec win32-g++
	${QMAKE} CONFIG+="${MODE}" WITH_BUILT_LIBS=1 STATIC="${STATIC}" ${QMAKE_PORTABLE_OPT} ${DEBUG_INFO_OPT} "${PROJECT_FILE}" -r -spec win32-g++
	${MAKE} clean
	${MAKE} ${MAKE_OPTS} || exit 1

	# ${MODE} contains 'debug' or 'release' which are both directories.
	rm -rf "${SRC_ROOT}/${APP_DIR}"
	mkdir -p "${SRC_ROOT}/${APP_DIR}"
	cp "${MODE}/${APP_NAME}.exe" "${SRC_ROOT}/${APP_DIR}/" || exit 1

	# Build CLI version.
	echo ${QMAKE} CONFIG+="${MODE}" WITH_BUILT_LIBS=1 STATIC="${STATIC}" ${QMAKE_PORTABLE_OPT} ${DEBUG_INFO_OPT} "${CLI_PROJECT_FILE}" -r -spec win32-g++
	${QMAKE} CONFIG+="${MODE}" WITH_BUILT_LIBS=1 STATIC="${STATIC}" ${QMAKE_PORTABLE_OPT} ${DEBUG_INFO_OPT} "${CLI_PROJECT_FILE}" -r -spec win32-g++
	${MAKE} clean
	${MAKE} ${MAKE_OPTS} || exit 1
	cp "${MODE}/${CLI_APP_NAME}.exe" "${SRC_ROOT}/${APP_DIR}/" || exit 1

	popd

	if [ "x${BUILD_TYPE}" = "x${BUILD_SHARED}" ]; then
		echo "${SRC_ROOT}"/scripts/windows_bundle_shared_libs.sh -a "${APP_NAME}" -b "${APP_DIR}" ${PARAM_MODE} -v "${VARIANT}" --${ARCH_NAME} --deployqt "${WINDEPLOYQT}" ${USE_EAY32}
		# Intentionally not exiting directly after exiting with non-zero exit code.
		"${SRC_ROOT}"/scripts/windows_bundle_shared_libs.sh -a "${APP_NAME}" -b "${APP_DIR}" ${PARAM_MODE} -v "${VARIANT}" --${ARCH_NAME} --deployqt "${WINDEPLOYQT}" ${USE_EAY32}
		EXIT_CODE="$?"
		if [ "${EXIT_CODE}" -eq "2" ]; then
			# Something unexpected happened while bundling Qt.
			BUNDLING_WARNING="Check the bundled Qt plug-ins as there may be a problem there."
		elif [ "${EXIT_CODE}" -ne "0" ]; then
			exit 1
		fi
		unset EXIT_CODE
	fi
fi

if [ "x${BUILD_PACKAGES}" != "xno" ]; then
	BINARY="${APP_DIR}/${APP_NAME}.exe"
	if [ ! -x "${BINARY}" ]; then
		echo "Cannot find '${BINARY}'. Run the compilation." >&2
		exit 1
	fi
	unset BINARY

	echo "${SRC_ROOT}"/scripts/windows_build_packages.sh --app "${APP_NAME}" --architecture "${ARCH_NAME}" --bundle "${APP_DIR}" --variant "${VARIANT}" --pkg-version "${PKG_VER}"
	"${SRC_ROOT}"/scripts/windows_build_packages.sh --app "${APP_NAME}" --architecture "${ARCH_NAME}" --bundle "${APP_DIR}" --variant "${VARIANT}" --pkg-version "${PKG_VER}" || exit 1
	# Remember the exit code,
	EXIT_CODE="$?"
	# Print a warning if needed.
	if [ "x${BUNDLING_WARNING}" != "x" ]; then
		echo "${BUNDLING_WARNING}" >&2
	fi
	if [ "${EXIT_CODE}" -ne "0" ]; then
		exit 1
	fi
	unset EXIT_CODE
fi
