// =====================================================================================================================
//  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/window.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_WINDOW_H
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H

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

#include <fennec/math/ext/rect.h>

#include <fennec/string/string.h>

#include <fennec/containers/bitfield.h>
#include <fennec/containers/optional.h>
#include <fennec/memory/pointers.h>

namespace fennec
{

///
/// \brief base window interface
class window {
// Definitions =========================================================================================================
public:

	/// \name Definitions
	/// @{

	///
	/// \brief window mode
	enum mode_ : uint8_t {
		mode_windowed = 0, //!< normal window mode
		mode_minimized,    //!< minimized to the taskbar
		mode_maximized,    //!< maximized to take up the whole screen
		mode_fullscreen,   //!< window surface takes the whole screen without border decorations
		mode_exclusive_fullscreen, //!< takes exclusive control of the display
	};

	///
	/// \brief vsync mode
	enum vsync_ : uint8_t {
		vsync_disabled = 0, //!< no vertical sync
		vsync_enabled,      //!< enabled vertical sync
		vsync_adaptive      //!< adaptive sync
	};

	///
	/// \brief window behaviour flags
	enum flag_ : uint8_t {
		flag_always_on_top = 0, //!< Window always appears on top level
		flag_borderless,        //!< Window has no border decorations
		flag_modal,             //!< Window always appears above parent and blocks input going to parent
		flag_pass_mouse,        //!< Mouse interaction passes to next underlying window in the application
		flag_popup,             //!< Window does not show in taskbar and closes when loses focus
		flag_resizable,         //!< Window can be resized through functions defined by Desktop Environment
		flag_transparent,       //!< Window has an alpha value
		flag_no_focus,          //!< Window can be focused

		flag_count //!< the number of flags
	};

	///
	/// \brief window state flags
	enum state_ : uint8_t {
		state_running = 0, // Window is running
		state_child,       // Window is a child
		state_suspended,   // Window is suspended
		state_visible,     // Window is visible

		state_count
	};

	using flags_t = bitfield<flag_count>;  //!< flag bitset
	using state_t = bitfield<state_count>; //!< state bitset

	///
	/// \brief accessibility information
	struct accessibility {
		string name;        //!< the name of the window provided to accessibility features
		string description; //!< the description of the window provided to accessibility features
	};

	///
	/// \brief window configuration
	struct config {
		string  title; //!< title of the window
		flags_t flags; //!< window behaviour flags
		uint8_t mode;  //!< the window mode

		irect  rect; //!< the bounds of the window

		double_t fractional_scaling; //!< fractional scaling factor

		accessibility accessibility; //!< accessibility info
	};

	///
	/// \brief window state info
	struct state {
		uint8_t  mode;               //!< the current window mode
		irect    rect;               //!< the current bounds of the window
		state_t  flags;              //!< the current behaviour flags of the window
		int_t    buffer_scale;       //!< buffer scaling
		double_t fractional_scaling; //!< current fractional scaling factor
	};

	/// @}



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

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

	///
	/// \brief window constructor
	/// \param server the display server the window belongs to
	/// \param conf the configuration to construct the window with
	/// \param parent a reference to the parent window
	window(display_server* server, const config& conf, window* parent);

	///
	/// \brief base destructor
	virtual ~window();

	/// @}



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

	/// \name Properties
	/// @{

	///
	/// \returns the current configuration of the window
	const config& get_config() const {
		return cfg;
	}

	///
	/// \returns the parent window
	window* get_parent() const {
		return parent;
	}

	///
	/// \returns the nearest top-level window in the hierarchy
	window* get_root() const {
		return root;
	}

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

	/// @}



// Positional Info =====================================================================================================
public:

	/// \name Screen Bounds
	/// @{

	///
	/// \returns the size of the window
	const ivec2& get_size()     const {
		return state.rect.size;
	}

	///
	/// \returns the position of the window
	const ivec2& get_position() const {
		return state.rect.position;
	}

	///
	/// \returns the bounds of the window
	const irect& get_bounds() const {
		return state.rect;
	}

	///
	/// \returns the width of the window
	int get_width() const {
		return state.rect.size.x;
	}

	///
	/// \returns the height of the window
	int get_height() const {
		return state.rect.size.y;
	}

	///
	/// \returns the x position of the window
	int get_pos_x() const {
		return state.rect.position.x;
	}

	///
	/// \returns the y position of the window
	int get_pos_y() const {
		return state.rect.position.y;
	}

	virtual void set_size(const ivec2& size) = 0;

	/// @}



// Status ==============================================================================================================
public:

	/// \name Status
	/// @{

	///
	/// \brief tests if the window is visible
	/// \returns \emph{true} if the window is visible, \emph{false} otherwise
	bool is_visible()   const { return state.flags.test(state_visible);   }

	///
	/// \brief tests if the window is a child
	/// \returns \emph{true} if the window is a child, \emph{false} otherwise
	bool is_child()     const { return state.flags.test(state_child); }

	///
	/// \brief tests if the window is running
	/// \returns \emph{true} if the window is running, \emph{false} otherwise
	bool is_running()   const { return state.flags.test(state_running);   }

	///
	/// \brief tests if the window is suspended
	/// \returns \emph{true} if the window is suspended, \emph{false} otherwise
	bool is_suspended() const { return state.flags.test(state_suspended); }

	/// @}



// Behaviour ===========================================================================================================
public:

	/// \name Behaviour Flags
	/// @{

	///
	/// \brief tests a specific flag
	/// \param flag the flag from `window::flag_`
	/// \returns \emph{true} if the flag is set, \emph{false} otherwise
	bool get_flag(uint8_t flag) const { return cfg.flags.test(flag); }


	///
	/// \brief check if the window is flagged to always be on top of other windows
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_always_on_top() const { return get_flag(flag_always_on_top); }

	///
	/// \brief check if the window is flagged to have no window decorations
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_borderless() const { return get_flag(flag_borderless); }

	///
	/// \brief check if the window is flagged to be modal
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_modal() const { return get_flag(flag_modal); }

	///
	/// \brief check if the window is flagged to pass mouse input to windows underneath from the same application
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_passing_mouse() const { return get_flag(flag_pass_mouse); }

	///
	/// \brief check if the window is flagged as a popup
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_popup() const { return get_flag(flag_popup); }

	///
	/// \brief check if the window is flagged to be resizable
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_resizable() const { return get_flag(flag_resizable); }

	///
	/// \brief check if the window is flagged to be transparent
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_transparent() const { return get_flag(flag_transparent); }

	///
	/// \brief check if the window is flagged to be unfocusable
	/// \returns \emph{true} if set, \emph{false} otherwise
	bool is_no_focus() const { return get_flag(flag_no_focus); }


	///
	/// \brief sets a specific flag
	/// \param flag the flag from `window::flag_`
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	virtual bool set_flag(uint8_t flag, bool val) = 0;

	///
	/// \brief sets whether to always be on top of other windows
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_always_on_top(bool val) { return set_flag(flag_always_on_top, val); }

	///
	/// \brief sets whether to have no window decorations
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_borderless(bool val) { return set_flag(flag_borderless, val); }

	///
	/// \brief sets whether to be modal
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_modal(bool val) { return set_flag(flag_modal, val); }

	///
	/// \brief sets whether to pass mouse input to windows underneath from the same application
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_passing_mouse(bool val) { return set_flag(flag_pass_mouse, val); }

	///
	/// \brief sets whether the window is a popup
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_popup(bool val) { return set_flag(flag_popup, val); }

	///
	/// \brief sets whether to be resizable
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_resizable(bool val) { return set_flag(flag_resizable, val); }

	///
	/// \brief sets whetherto be transparent
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_transparent(bool val) { return set_flag(flag_transparent, val); }

	///
	/// \brief sets whether to be unfocusable
	/// \param val the value to set the flag to
	/// \returns \emph{true} on success, \emph{false} otherwise
	bool set_no_focus(bool val) { return set_flag(flag_no_focus, val); }

	/// @}



// Initialization & Update =============================================================================================
public:

	/// \name Initialization & Update
	/// @{

	virtual void initialize() = 0; //!< initialization function
	virtual void shutdown() = 0;   //!< shutdown function

	virtual void begin_frame(); //!< start a frame for the window, setting the correct graphics context
	virtual void end_frame();   //!< end a frame for the window, swapping the underlying buffers

	/// @}


// Protected Member Variables ==========================================================================================
public:
	display_server* const server;      //!< the display server the window belongs to
	window*         const parent;      //!< the parent window
	window*         const root;        //!< the nearest top-level window in the hierarchy

protected:
	config                 cfg;         //!< the current configuration
	state                  state;       //!< the current state
	unique_ptr<gfxsurface> gfx_surface; //!< the corresponding graphics surface
};

///
/// \brief Interface resembling the API for a window of a display server
template<typename DisplayT>
class window_base : public window {
public:
	///
	/// \brief constructor
	/// \param display the display server
	/// \param conf the configuration
	/// \param parent the parent window
	window_base(display_server* display, const config& conf, window* parent)
		: window(display, conf, parent) {
	}

	using display_t = DisplayT; //!< corresponding display server type
};

}

#endif // FENNEC_PLATFORM_INTERFACE_WINDOW_H