////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////

#ifndef SFML_WINDOWIMPLWIN32_HPP
#define SFML_WINDOWIMPLWIN32_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "../Event.hpp"
#include "../WindowImpl.hpp"
#include "../String.hpp"
#include <windows.h>


namespace sf {
	namespace priv {
		////////////////////////////////////////////////////////////
		/// \brief Windows implementation of WindowImpl
		///
		////////////////////////////////////////////////////////////
		class WindowImplWin32 : public WindowImpl {
		public:

			////////////////////////////////////////////////////////////
			/// \brief Construct the window implementation from an existing control
			///
			/// \param handle Platform-specific handle of the control
			///
			////////////////////////////////////////////////////////////
			WindowImplWin32(WindowHandle handle);

			////////////////////////////////////////////////////////////
			/// \brief Create the window implementation
			///
			/// \param mode  Video mode to use
			/// \param title Title of the window
			/// \param style Window style
			/// \param settings Additional settings for the underlying OpenGL context
			///
			////////////////////////////////////////////////////////////
			WindowImplWin32(VideoMode mode, const String& title, Uint32 style);

			////////////////////////////////////////////////////////////
			/// \brief Destructor
			///
			////////////////////////////////////////////////////////////
			~WindowImplWin32();

			////////////////////////////////////////////////////////////
			/// \brief Get the OS-specific handle of the window
			///
			/// \return Handle of the window
			///
			////////////////////////////////////////////////////////////
			virtual WindowHandle getSystemHandle() const;

			////////////////////////////////////////////////////////////
			/// \brief Get the position of the window
			///
			/// \return Position of the window, in pixels
			///
			////////////////////////////////////////////////////////////
			virtual Vector2i getPosition() const;

			////////////////////////////////////////////////////////////
			/// \brief Change the position of the window on screen
			///
			/// \param position New position of the window, in pixels
			///
			////////////////////////////////////////////////////////////
			virtual void setPosition(const Vector2i& position);

			////////////////////////////////////////////////////////////
			/// \brief Get the client size of the window
			///
			/// \return Size of the window, in pixels
			///
			////////////////////////////////////////////////////////////
			virtual Vector2u getSize() const;

			////////////////////////////////////////////////////////////
			/// \brief Change the size of the rendering region of the window
			///
			/// \param size New size, in pixels
			///
			////////////////////////////////////////////////////////////
			virtual void setSize(const Vector2u& size);

			////////////////////////////////////////////////////////////
			/// \brief Change the title of the window
			///
			/// \param title New title
			///
			////////////////////////////////////////////////////////////
			virtual void setTitle(const String& title);

			////////////////////////////////////////////////////////////
			/// \brief Change the window's icon
			///
			/// \param width  Icon's width, in pixels
			/// \param height Icon's height, in pixels
			/// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
			///
			////////////////////////////////////////////////////////////
			virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);

			////////////////////////////////////////////////////////////
			/// \brief Show or hide the window
			///
			/// \param visible True to show, false to hide
			///
			////////////////////////////////////////////////////////////
			virtual void setVisible(bool visible);

			////////////////////////////////////////////////////////////
			/// \brief Show or hide the mouse cursor
			///
			/// \param visible True to show, false to hide
			///
			////////////////////////////////////////////////////////////
			virtual void setMouseCursorVisible(bool visible);

			////////////////////////////////////////////////////////////
			/// \brief Grab or release the mouse cursor
			///
			/// \param grabbed True to enable, false to disable
			///
			////////////////////////////////////////////////////////////
			virtual void setMouseCursorGrabbed(bool grabbed);

			////////////////////////////////////////////////////////////
			/// \brief Set the displayed cursor to a native system cursor
			///
			/// \param cursor Native system cursor type to display
			///
			////////////////////////////////////////////////////////////
			virtual void setMouseCursor(const CursorImpl& cursor);

			////////////////////////////////////////////////////////////
			/// \brief Enable or disable automatic key-repeat
			///
			/// \param enabled True to enable, false to disable
			///
			////////////////////////////////////////////////////////////
			virtual void setKeyRepeatEnabled(bool enabled);

			////////////////////////////////////////////////////////////
			/// \brief Request the current window to be made the active
			///        foreground window
			///
			////////////////////////////////////////////////////////////
			virtual void requestFocus();

			////////////////////////////////////////////////////////////
			/// \brief Check whether the window has the input focus
			///
			/// \return True if window has focus, false otherwise
			///
			////////////////////////////////////////////////////////////
			virtual bool hasFocus() const;

		protected:

			////////////////////////////////////////////////////////////
			/// \brief Process incoming events from the operating system
			///
			////////////////////////////////////////////////////////////
			virtual void processEvents();

		private:

			////////////////////////////////////////////////////////////
			/// Register the window class
			///
			////////////////////////////////////////////////////////////
			void registerWindowClass();

			////////////////////////////////////////////////////////////
			/// \brief Switch to fullscreen mode
			///
			/// \param mode Video mode to switch to
			///
			////////////////////////////////////////////////////////////
			void switchToFullscreen(const VideoMode& mode);

			////////////////////////////////////////////////////////////
			/// \brief Free all the graphical resources attached to the window
			///
			////////////////////////////////////////////////////////////
			void cleanup();

			////////////////////////////////////////////////////////////
			/// \brief Process a Win32 event
			///
			/// \param message Message to process
			/// \param wParam  First parameter of the event
			/// \param lParam  Second parameter of the event
			///
			////////////////////////////////////////////////////////////
			void processEvent(UINT message, WPARAM wParam, LPARAM lParam);

			////////////////////////////////////////////////////////////
			/// \brief Enables or disables tracking for the mouse cursor leaving the window
			///
			/// \param track True to enable, false to disable
			///
			////////////////////////////////////////////////////////////
			void setTracking(bool track);

			////////////////////////////////////////////////////////////
			/// \brief Grab or release the mouse cursor
			///
			/// This is not to be confused with setMouseCursorGrabbed.
			/// Here m_cursorGrabbed is not modified; it is used,
			/// for example, to release the cursor when switching to
			/// another application.
			///
			/// \param grabbed True to enable, false to disable
			///
			////////////////////////////////////////////////////////////
			void grabCursor(bool grabbed);

			////////////////////////////////////////////////////////////
			/// \brief Convert a Win32 virtual key code to a SFML key code
			///
			/// \param key   Virtual key code to convert
			/// \param flags Additional flags
			///
			/// \return SFML key code corresponding to the key
			///
			////////////////////////////////////////////////////////////
			static Keyboard::Key virtualKeyCodeToSF(WPARAM key, LPARAM flags);

			////////////////////////////////////////////////////////////
			/// \brief Function called whenever one of our windows receives a message
			///
			/// \param handle  Win32 handle of the window
			/// \param message Message received
			/// \param wParam  First parameter of the message
			/// \param lParam  Second parameter of the message
			///
			/// \return True to discard the event after it has been processed
			///
			////////////////////////////////////////////////////////////
			static LRESULT CALLBACK globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);

			////////////////////////////////////////////////////////////
			/// \brief Convert a Win32 scancode to an sfml scancode
			///
			/// \param flags input flags
			///
			/// \return SFML scancode corresponding to the key
			///
			////////////////////////////////////////////////////////////
			static Keyboard::Scancode toScancode(WPARAM wParam, LPARAM lParam);

			////////////////////////////////////////////////////////////
			// Member data
			////////////////////////////////////////////////////////////
			HWND     m_handle;           //!< Win32 handle of the window
			LONG_PTR m_callback;         //!< Stores the original event callback function of the control
			bool     m_cursorVisible;    //!< Is the cursor visible or hidden?
			HCURSOR  m_lastCursor;       //!< Last cursor used -- this data is not owned by the window and is required to be always valid
			HICON    m_icon;             //!< Custom icon assigned to the window
			bool     m_keyRepeatEnabled; //!< Automatic key-repeat state for keydown events
			Vector2u m_lastSize;         //!< The last handled size of the window
			bool     m_resizing;         //!< Is the window being resized?
			Uint16   m_surrogate;        //!< First half of the surrogate pair, in case we're receiving a Unicode character in two events
			bool     m_mouseInside;      //!< Mouse is inside the window?
			bool     m_fullscreen;       //!< Is the window fullscreen?
			bool     m_cursorGrabbed;    //!< Is the mouse cursor trapped?
		};

	} // namespace priv

} // namespace sf

#endif // SFML_WINDOWIMPLWIN32_HPP