#ifndef GLWINDOW_H
#define GLWINDOW_H

#include <QWindow>

/*!
\file
Contains the \ref GLWindow class.
*/

/*!
A QWindow derivative capable of OpenGL drawing.
Modeled after http://qt-project.org/doc/qt-5/qtgui-openglwindow-example.html with some changes.

Before the window is first shown (before \c create is called), make sure to set a good surface format by calling \c setFormat.
The window uses its own OpenGL rendering context, which uses the specified format. The window owns the context, so it is no longer available after the window is destroyed.

Can be used as a widget by using \ref createWindowContainer.
All subclasses get automatic access to OpenGL ES 2.0 functions.

\see http://www.khronos.org/opengles/2_X/
*/
class GLWindow : public QWindow, protected QOpenGLFunctions
{
	Q_OBJECT

public:
	explicit GLWindow(QWindow *parent = nullptr);
	~GLWindow();

	/*!
		Creates a window container from this \c GLWindow. 
		Just calls <tt>QWidget::createWindowContainer</tt> with the specified parameters.

		\param parent the parent of the returned widget.
		\param flags the window flags to be used
		\returns a new widget which is a container for this \c GLWindow
	*/
	QWidget* createWindowContainer(QWidget* parent = nullptr, Qt::WindowFlags flags = nullptr);

	/*!
	Gets if the window is currently in animation mode.
	\see setAnimating
	*/
	bool isAnimating() const { return m_animating; }

	/*!
	Returns the currently used surface format. This is the format of the \c QOpenGLContext if it exists, otherwise the \ref requestedFormat is returned.
	*/
	QSurfaceFormat format() const override { return m_context ? m_context->format() : requestedFormat(); }

signals:
	/*!
	This signal is sent when the context creation has failed, or the \ref initialize function returned an error.
	The window is unusable in this case.
	\param error an error string suitable for user display
	*/
	void initializeFailed(const QString& error);

public slots:
	/*!
	Enables/disables animation mode.
	In animation mode, the window is continually rendering. 
	This is done by calling \ref renderLater after each \ref renderNow call has finished, 
	causing continuous rendering requests until \c setAnimating(false) is called.
	Note that this method is unsuitable for high-performance, low-delay animations like games.
	*/
	void setAnimating(bool animating) { m_animating = animating; if(animating) renderLater(); }

	/*!
	Queues a render request using the Qt event queue, to be executed at a later time.
	Call this after updating drawing parameters. The request will call \ref renderNow.
	*/
    void renderLater();
	/*!
	Makes sure everything is correctly initialized, calls \ref render and does buffer-swapping afterwards.
	This method has no effect if the window is not exposed. Additionally, if an error occured during initialization, nothing will be done.
	*/
    void renderNow();

protected:
	/*!
	Set to true if error occured making rendering impossible
	*/
	bool m_error;

    bool event(QEvent *event) override;
	//the window draws when exposed
    void exposeEvent(QExposeEvent *event) override;

	/*! 
	Provides a convenient point for subclasses to initialize. 
	Is guaranteed to be called before the window is first rendered.
	The default implementation does nothing.
	Subclasses should return false on error, 
	and also emit \ref initializeFailed with a user-readable message.
	/return false if error occurred during initialization
	*/
	virtual bool initialize();

	/*!
	Subclasses should implement this to render the window content.
	The caller has to assure that the GL context is bound and everything is initialized, 
	an easy way to do this is to call \ref renderNow. The default implementation just draws a red background.
	*/
	virtual void render();

	/*!
		The OpenGL context used for this window.
		Not available until first call to \ref renderNow.
	*/
	QOpenGLContext* m_context;

private:
	bool m_update_pending,m_animating,m_initializing;
	
};

#endif // GLWINDOW_H
