#ifndef CWINDOW_HPP
#define CWINDOW_HPP

#include "../../Controller/Exception/CLibException.hpp"
#include "../../Controller/Exception/CLogicException.hpp"

#include <cstdlib>
#include <string>
#include <utility>
#include <exception>
#include <stdexcept>
#include <SDL.h>
#ifdef WIN32
    #include <SDL_Image.h>
#else
    #include <SDL_image.h>
#endif

/**
 * @file CWindow.hpp
 * @brief File of CWindow, a class reprensenting a Window, using SDL2 lib.
 */

/**
 * @brief Class reprensenting a Window, using SDL2 lib.
 */
class CWindow {
private:
	// The title of the window.
	std::string m_title;

	// The path to the icon.
	std::string m_iconPath;

	// First is the width, second is the height.
	std::pair<unsigned int, unsigned int> m_size;

	// Say if the window is fullscreen.
	bool m_fullscreen;

	// Say if the window is visible.
	bool m_visible;

	// Say if the window is resizable.
	bool m_resizable;

	// SDL flags for creating the window.
	unsigned int m_sdlFlags;

	// The pointer to the window.
	SDL_Window* m_pwindow;

public:
	CWindow(void) = delete;
	CWindow(const CWindow& param) = delete;
	CWindow& operator=(const CWindow& param) = delete;

	/**
	 * @brief The default constructor, build a non visible window with size of widthxheight.
	 * @param[in] title The title of the window.
	 * @param[in] iconPath The iconPath of the window.
	 * @param[in] width The width of the window.
	 * @param[in] height The height of the window.
	 * @param[in] sdlFlags Allow to add SDL flags.
	 */
	CWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen, unsigned int sdlFlags);

	/**
	 * @brief The default constructor, build a non visible window with size of widthxheight.
	 * @param[in] title The title of the window.
	 * @param[in] The window to embed the game in.
	 * @param[in] sdlFlags Allow to add SDL flags.
	 * @param[in] imageFlags Allow to add SDL_Image flags.
	 */
	CWindow(std::string title, SDL_Window* window, unsigned int sdlFlags, unsigned int imageFlags);


	/**
	 * @brief The destructor.
	 */
	~CWindow(void);

	/**
	 * @brief Get the SDL_Window* of the window.
	 * @return SDL_Window The window, in SDL2 format.
	 */
	SDL_Window* getWindow(void);

	void setWindow(SDL_Window* window){m_pwindow = window; };
	/**
	 * @brief Say if the window is fullscreen.
	 * @return bool, a boolean which say the fullscreen status.
	 */
	bool isFullscreen(void) const;

	/**
	 * @brief Set the fullscreen status.
	 * @param[in] newFullscreen New value of fullscreen status.
	 */
	void setFullscreen(bool newFullscreen);

	/**
	 * @brief Say if the window is visible.
	 * @return bool, a boolean which say the visible status.
	 */
	bool isVisible(void) const;

	/**
	 * @brief Set the visibility status.
	 * @param[in] newVisible New value of visibility status.
	 */
	void setVisible(bool newVisible);

	/**
	 * @brief Get the window icon path.
	 * @return std::string, the path.
	 */
	std::string getIconPath(void) const;

	/**
	 * @brief Get the window title.
	 * @return std::string, the title.
	 */
	std::string getTitle(void) const;

	/**
	 * @brief Change the window title.
	 * @param[in] newTitle New title of the window.
	 */
	void setTitle(std::string newTitle);

	/**
	 * @brief Change the window icon.
	 * @param[in] newIconPath New icon path of the window.
	 */
	void setIconPath(std::string newIconPath);

	/**
	 * @brief Get the window width.
	 * @return unsigned int, the window width (in pixel).
	 */
	unsigned int getWidth(void) const;

	/**
	 * @brief Get the window height.
	 * @return unsigned int, the window height (in pixel).
	 */
	unsigned int getHeight(void) const;

	/**
	 * @brief Get the window size.
	 * @return std::pair<unsigned int, unsigned int>, the window size (in pixel).
	 */
	std::pair<unsigned int, unsigned int> getSize(void) const;

	/**
	 * @brief Set the window size.
	 * @param[in] newSize New value of window size.
	 */
	void setSize(std::pair<unsigned int, unsigned int> newSize);

	/**
	 * @brief Set the window size.
	 * @param[in] newWidth New value of window width.
	 * @param[in] newHeight New value of window height.
	 */
	void setSize(unsigned int newWidth, unsigned int newHeight);

	/**
	 * @brief Say if the window is resizable.
	 * @return bool, a boolean which say the resizable status.
	 */
	bool isResizable(void) const;

	/**
	 * @brief Set the rezisable status.
	 * @param[in] newResizable New value of rezisable status.
	 */
	void setResizable(bool newResizable);

	/**
	 * @brief Say if the window is initialized.
	 * @return bool, a boolean which say the initialization status.
	 */
	bool isInitialized(void) const;

	/**
	 * @brief Initialize the window.
	 * @post Give a error if the windows is already init.
	 */
	void initialization();

	/**
	 * @brief Launched before the creation of the window, usefull for setting OpenGL attribute.
	 */
	virtual void preinitialization() = 0;

	/**
	 * @brief Launched after the creation of the window, usefull for setting others attribute.
	 */
	virtual void postinitialization() = 0;
};

#endif