#pragma once

// Set default name and version if not provided by CMake
/** @brief Application name */
#if !defined(NCINE_APP)
#	define NCINE_APP "jazz2"
#endif
/** @brief Application full name */
#if !defined(NCINE_APP_NAME)
#	define NCINE_APP_NAME "Jazz² Resurrection"
#endif
/** @brief Application version */
#if !defined(NCINE_VERSION)
#	define NCINE_VERSION "3.8.0"
#endif
/**
	@brief Application multiplayer protocol version

	Decides whether a client and a server can play together, independently of @ref NCINE_VERSION. Set it to the
	application version in which the protocol last changed incompatibly --- packet types, property types, field
	layouts or the meaning of a field --- and leave it alone for releases that don't touch the wire, so those can
	still play together.
*/
#if !defined(NCINE_PROTOCOL_VERSION)
#	define NCINE_PROTOCOL_VERSION "3.8.0"
#endif
/** @brief Application build year */
#if !defined(NCINE_BUILD_YEAR)
#	define NCINE_BUILD_YEAR "2026"
#endif
/** @brief Application package name on Linux */
#if !defined(NCINE_LINUX_PACKAGE)
#	define NCINE_LINUX_PACKAGE NCINE_APP_NAME
#endif

// Prefer local version of shared libraries in CMake build
#if defined(CMAKE_BUILD) && defined(__has_include)
#	if __has_include("../Shared/Common.h")
#		define __HAS_LOCAL_COMMON
#	endif
#endif
#ifdef __HAS_LOCAL_COMMON
#	include "../Shared/Common.h"
#	include "../Shared/Asserts.h"
#else
#	include <Common.h>
#	include <Asserts.h>
#endif

#include <stdlib.h>

/** @brief Install prefix on Unix systems, usually `"/usr/local"` */
#if (!defined(NCINE_INSTALL_PREFIX) && defined(DEATH_TARGET_UNIX)) || defined(DOXYGEN_GENERATING_OUTPUT)
#	define NCINE_INSTALL_PREFIX "/usr/local"
#endif

// Check platform-specific capabilities
/** @brief Whether the current platform supports a gamepad rumble, see @relativeref{nCine,IInputManager::joystickRumble()} */
#if (defined(WITH_SDL2) || defined(WITH_SDL3)) || defined(DEATH_TARGET_ANDROID) || defined(DEATH_TARGET_WINDOWS_RT) || defined(DOXYGEN_GENERATING_OUTPUT)
#	define NCINE_HAS_GAMEPAD_RUMBLE
#endif
/** @brief Whether the current platform has a native (hardware) back button */
#if defined(DEATH_TARGET_ANDROID) || defined(DOXYGEN_GENERATING_OUTPUT)
#	define NCINE_HAS_NATIVE_BACK_BUTTON
#endif
/** @brief Whether the current platform supports vibrations of the device */
#if defined(DEATH_TARGET_ANDROID)
#	define NCINE_HAS_VIBRATIONS
#endif
/** @brief Whether the current platform has non-fullscreen windows */
#if !defined(DEATH_TARGET_ANDROID) && !defined(DEATH_TARGET_IOS) && !defined(DEATH_TARGET_SWITCH) && \
		!defined(DEATH_TARGET_DREAMCAST) && !defined(DEATH_TARGET_WII) && !defined(DEATH_TARGET_GAMECUBE) && \
		!defined(DEATH_TARGET_PSP) && !defined(DEATH_TARGET_VITA) && !defined(DEATH_TARGET_PS2) && \
		!defined(DEATH_TARGET_PS3)
#	define NCINE_HAS_WINDOWS
#endif
/**
	@brief Whether the current platform can have a touchscreen

	Listed rather than excluded, so a platform that has no touchscreen doesn't acquire one by not being
	mentioned - which is how the consoles ended up offering to configure touch controls.
*/
#if defined(DEATH_TARGET_ANDROID) || defined(DEATH_TARGET_IOS) || defined(DEATH_TARGET_EMSCRIPTEN) || \
		defined(DEATH_TARGET_SWITCH) || defined(DEATH_TARGET_VITA) || \
		defined(DEATH_TARGET_WINDOWS) || defined(DEATH_TARGET_UNIX) || defined(DOXYGEN_GENERATING_OUTPUT)
#	define NCINE_HAS_TOUCH_CONTROLS
#endif
/**
	@brief Whether the current platform can drive the RGB lighting of connected devices

	Only Windows (through the Razer Chroma™ SDK) and the web build (through a local bridge) actually do so;
	the other desktop platforms are included because that is where such a device is plugged in, and where
	@relativeref{Jazz2::Input,RgbLights} could gain a backend without the option having to reappear.
*/
#if (defined(DEATH_TARGET_WINDOWS) && !defined(DEATH_TARGET_WINDOWS_RT)) || defined(DEATH_TARGET_EMSCRIPTEN) || \
		defined(DEATH_TARGET_UNIX) || (defined(DEATH_TARGET_APPLE) && !defined(DEATH_TARGET_IOS)) || \
		defined(DOXYGEN_GENERATING_OUTPUT)
#	define NCINE_HAS_RGB_LIGHTS
#endif
/**
	@brief Whether the current platform can convert the original game data into a cache of its own

	The Dreamcast and PlayStation 2 play from a disc and the GameCube has nowhere to put a cache
	the size of a converted installation, and the web build is prepared entirely ahead of time - none
	of the three can write one, so they consume a content tree prebaked with @ref asset-packer
	"AssetPacker", skip the conversion altogether and never look for the original game files,
	which are not there in the first place.

	Everywhere else the first-run conversion exists, including the PlayStation Portable and the Wii,
	where the content sits on a writable memory stick or SD card. Those two are usually given a prebaked
	tree as well, which is recognized at runtime rather than assumed here, see
	@relativeref{Jazz2,ContentResolver::IsContentPrebaked()}.
*/
#if !defined(DEATH_TARGET_EMSCRIPTEN) && !defined(DEATH_TARGET_DREAMCAST) && !defined(DEATH_TARGET_GAMECUBE) && !defined(DEATH_TARGET_PS2)
#	define NCINE_HAS_WRITABLE_CACHE
#endif

/** @brief Function name */
#if defined(__DEATH_CURRENT_FUNCTION)
#	define NCINE_CURRENT_FUNCTION __DEATH_CURRENT_FUNCTION
#else
#	define NCINE_CURRENT_FUNCTION ""
#endif

#ifndef DOXYGEN_GENERATING_OUTPUT

// Return assert macros
#define RETURN_ASSERT(x) do { if DEATH_UNLIKELY(!(x)) { LOGE("RETURN_ASSERT(" #x ")"); return; } } while (false)

// Return false assert macros
#define RETURNF_ASSERT(x) do { if DEATH_UNLIKELY(!(x)) { LOGE("RETURNF_ASSERT(" #x ")"); return false; } } while (false)

// Fatal assert macros
#define FATAL_ASSERT(x)						\
	do {									\
		if DEATH_UNLIKELY(!(x)) {			\
			LOGF("FATAL_ASSERT(" #x ")");	\
			DEATH_ASSERT_BREAK();			\
		}									\
	} while (false)

#define FATAL_ASSERT_MSG(x, fmt, ...)		\
	do {									\
		if DEATH_UNLIKELY(!(x)) {			\
			LOGF(fmt, ##__VA_ARGS__);		\
			DEATH_ASSERT_BREAK();			\
		}									\
	} while (false)

#endif
