// =====================================================================================================================
//  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/platform/interface/display_server.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_PLATFORM_INTERFACE_DISPLAY_SERVER_H
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H

#include <fennec/containers/bitfield.h>

#include <fennec/platform/interface/forward.h>
#include <fennec/platform/interface/window.h>

#include <fennec/renderers/interface/gfxcontext.h>

#include <fennec/rtti/enable.h>
#include <fennec/rtti/type_registry.h>

namespace fennec
{

class display_server;

///
/// \brief Interface resembling the API for a display server of an operating system, e.g. Linux X11/Wayland
///
/// \details An implementation for a display server should inherit `display_server_base` and note the following:
///
///          For a server type \emph{DisplayT}; any `gfxcontext` implementation that wishes to implement \emph{DisplayT}
///          must provide a constructor that accepts a \emph{DisplayT*}. `DisplayT::ctx_registry::register_type()` must then be
///          called for the `gfxcontext` implementation.
class display_server : public type_registry<display_server, platform*> {
// Definitions & Constants =============================================================================================
public:

	/// \name Definitions
	/// @{

	///
	/// \brief enum representing features to test support for against the display server
	enum feature_ : uint32_t {
		feature_subwindows = 0, //!< sub window support
		feature_icon,           //!< icon support

		feature_window_drag, //!< window dragging support

		feature_mouse,          //!< mouse support
		feature_cursors,        //!< multiple cursor type support
		feature_custom_cursors, //!< custom cursor image support

		feature_clipboard,         //!< clipboard support
		feature_clipboard_primary, //!< highlight support
		feature_virtual_keyboard,  //!< virtual keyboard support

		feature_status_indicators,       //!< taskbar status indicators
		feature_dialogues,               //!< popup dialog support
		feature_input_dialogues,         //!< popup dialog text input support
		feature_file_dialogues,          //!< file navigation support
		feature_filtered_file_dialogues, //!< filtered file navigation support

		feature_orientation,         //!< display orientation support
		feature_hidpi,               //!< high dpi support
		feature_hdr,                 //!< hdr support
		feature_swap_buffers,        //!< swap buffer support
		feature_window_transparency, //!< window transparency support

		feature_screen_reader,  //!< screen reader support
		feature_text_to_speech, //!< text to speech system support
		feature_touchscreen,    //!< touchscreen support
		feature_system_theme,   //!< system specified theming

		feature_count, //!< number of features
	};

	using featureset_t = bitfield<feature_count>; //!< a bitset holding the supported feature set

	/// @}


// Public Member Variables =============================================================================================
public:
	platform* const platform; //!< the parent platform


// Constructors ========================================================================================================
public:

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

	///
	/// \brief display server constructor
	/// \param p the parent platform
	explicit display_server(fennec::platform* p)
		: platform(p) {
	}

	///
	/// \brief base destructor
	virtual ~display_server() = default;

	/// @}


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

	/// \name Properties
	/// @{

	///
	/// \brief feature support checking function
	/// \param feature the feature to check
	/// \returns \emph{true} if the feature is supported, \emph{false} otherwise
	bool has_feature(uint32_t feature) const {
		return features.test(feature);
	}

	///
	/// \returns \emph{true} if connected to the display server, \emph{false} otherwise
	virtual bool connected() const = 0;

	/// @}


// Operations ==========================================================================================================
public:

	/// \name Operations
	/// @{

	///
	/// \brief create a new window with the specified configuration and parent
	/// \param cfg the configuration
	/// \param p the parent window
	/// \returns the created window
	virtual window* create_window(const window::config& cfg, window* p = nullptr) = 0;

	///
	/// \brief connect to the display server
	virtual void connect()         = 0;

	///
	/// \brief disconnect from the display server
	virtual void disconnect()      = 0;

	///
	/// \brief dispatch the current context to the display server
	virtual void dispatch() = 0;

	///
	/// \returns the underlying native handle
	virtual void* get_native_handle() = 0;

	///
	/// \returns the graphics context of the display connection
	gfxcontext* get_gfx_context() {
		return gfx_context.get();
	}

	/// @}

// Protected Member Variables ==========================================================================================
protected:
	featureset_t           features;    //!< the feature set of the display server
	unique_ptr<gfxcontext> gfx_context; //!< the graphics context of the display server

private:
	FENNEC_RTTI_CLASS_ENABLE() {
	}
};

///
/// \brief Interface resembling the API for a display server of an operating system, e.g. Linux X11/Wayland
template<typename DisplayT, typename WindowT>
class display_server_base : public display_server, public type_registry<gfxcontext, DisplayT*> {
public:
	///
	/// \brief display server constructor
	/// \param p the parent platform
	display_server_base(fennec::platform* p)
		: display_server(p) {
	}

	using ctx_registry = type_registry<gfxcontext, DisplayT*>; //!< registry for graphics contexts
	using window_t     = WindowT;                              //!< the window type of the display server
};

}

#endif // FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H