// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file fennec/renderers/vulkan/lib/app_info.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H
#define FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H

#include <fennec/renderers/vulkan/lib/forward.h>

#include <fennec/core/version.h>
#include <fennec/string/cstring.h>

namespace fennec::vk
{

///
/// \brief Wrapper class for VkApplicationInfo
struct app_info : private VkApplicationInfo {

// Definitions =========================================================================================================
private:




// Constructors & Destructor ===========================================================================================
public:

	/// \name Constructors & Destructor
	/// @{

	///
	/// \brief Create a Vulkan application information structure
	/// \param app_name the name of the application.
	/// \param app_version the internal version of the application
	/// \param engine_name the name of the engine.
	/// \param engine_version the internal version of the engine
	/// \param ext a pointer to an extension structure, the object next points to must exist for the lifetime of this
	///            object until a structure of type fennec::vk::instance is constructed
	///            TODO: DEFINE EXTENSION STRUCTURE WRAPPERS
	app_info(
			const cstring& app_name    = {}, const version& app_version    = {},
			const cstring& engine_name = {}, const version& engine_version = {}
	) noexcept : VkApplicationInfo {
		.sType              = VK_STRUCTURE_TYPE_APPLICATION_INFO,
		.pNext              = nullptr,
		.pApplicationName   = nullptr,
		.applicationVersion = VK_MAKE_VERSION(app_version.major, app_version.minor, app_version.patch),
		.pEngineName        = nullptr,
		.engineVersion      = VK_MAKE_VERSION(engine_version.major, engine_version.minor, engine_version.patch),
		.apiVersion         = VK_MAKE_API_VERSION(0, 1, 0, 0), // Default to 1.0
	},	_app_name(app_name)
	,	_engine_name(engine_name) {

		pApplicationName = _app_name.data();
		pEngineName      = _engine_name.data();

		// Attempt to acquire version supported by the driver
		if (vkEnumerateInstanceVersion) {
			uint32_t api_version;
			vkEnumerateInstanceVersion(&api_version);
			apiVersion = VK_MAKE_API_VERSION(0, VK_API_VERSION_MAJOR(api_version), VK_API_VERSION_MINOR(api_version), 0);
		}
	}

	///
	/// \brief Copy Constructor
	app_info(const app_info&) noexcept = default;

	///
	/// \brief Move Constructor
	app_info(app_info&&) noexcept = default;

	///
	/// \brief Destructor
	~app_info() noexcept = default;

	/// @}


// Assignment Operators ================================================================================================
public:

	/// \name Assignment Operators
	/// @{

	///
	/// \brief Copy Assignment
	/// \param info The app_info object to move
	/// \returns A reference to \emph{this}
	app_info& operator=(const app_info& info) noexcept = default;

	///
	/// \brief Move Assignment
	/// \param info The app_info object to move
	/// \returns A reference to \emph{this}
	app_info& operator=(app_info&& info) noexcept = default;

	/// @}


// Implicit Conversions ================================================================================================
public:

	/// \name Implicit Conversions
	/// @{

	///
	/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
	operator VkApplicationInfo*() noexcept {
		return this;
	}

	///
	/// \brief Implicit Pointer Conversion
	/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
	operator const VkApplicationInfo*() const noexcept {
		return this;
	}

	/// @}


// Properties ==========================================================================================================
public:

	/// \name Properties
	/// @{

	///
	/// \returns A cstring containing the application name
	cstring get_app_name() const {
		return cstring(pApplicationName, strlen(pApplicationName));
	}

	///
	/// \brief Set the application name
	/// \param str A cstring containing the new name
	void set_app_name(const cstring& str) {
		pApplicationName = str;
	}

	///
	/// \returns A version struct containing the application version
	version get_app_version() const {
		return version {
			.major = VK_VERSION_MAJOR(applicationVersion),
			.minor = VK_VERSION_MINOR(applicationVersion),
			.patch = VK_VERSION_PATCH(applicationVersion)
		};
	}

	///
	/// \brief Set the engine version
	/// \param ver A version struct containing the new version
	void set_app_version(const version& ver) {
		applicationVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
	}

	///
	/// \returns A cstring containing the engine name
	cstring get_engine_name() const {
		return { pEngineName, strlen(pEngineName) };
	}

	///
	/// \brief Set the engine name
	/// \param str A cstring containing the new name
	void set_engine_name(const cstring& str) {
		pEngineName = str;
	}

	///
	/// \returns A version struct containing the engine version
	version get_engine_version() const {
		return version {
			.major = VK_VERSION_MAJOR(engineVersion),
			.minor = VK_VERSION_MINOR(engineVersion),
			.patch = VK_VERSION_PATCH(engineVersion)
		};
	}

	///
	/// \brief Set the engine version
	/// \param ver A version struct containing the new version
	void set_engine_version(const version& ver) {
		engineVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
	}

	///
	/// \returns A version struct containing the Vulkan API version
	version get_api_version() const {
		return version {
			.major = VK_API_VERSION_MAJOR(apiVersion),
			.minor = VK_API_VERSION_MINOR(apiVersion),
			.patch = VK_API_VERSION_PATCH(apiVersion),
			.meta  = VK_API_VERSION_VARIANT(apiVersion),
		};
	}

	///
	/// \brief Set the Vulkan API version
	/// \param ver A version struct containing the new version
	void set_api_version(const version& ver) {
		apiVersion = VK_MAKE_API_VERSION(0, ver.major, ver.minor, 0);
	}

	///
	/// \brief Set the extension structure
	/// \param ext A pointer to the new extension object
	void set_extension(void* ext) {
		pNext = ext;
	}

	///
	/// \brief Clear the extension structure with \emph{nullptr}
	void set_extension(nullptr_t) {
		pNext = nullptr;
	}

	/// @}


// Private Member Variables ============================================================================================
private:
	string _app_name;
	string _engine_name;
};

}

#endif // FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H