// Copyright (c) 2021 - 2022 kio@little-bat.de
// BSD-2-Clause license
// https://opensource.org/licenses/BSD-2-Clause

#pragma once
#include "kio/kio.h"
#include "enums.h"
#include "Image.h"
#include <QWidget>
#include <QPen>
#include <QOpenGLWindow>
#include <QOpenGLWidget>
#include <functional>
#include <mutex>


namespace gterm
{

class GTermWindow : public QOpenGLWindow
{
	Q_OBJECT
	Q_DISABLE_COPY_MOVE(GTermWindow)

	ScalingMode  scaling_mode  = SM_SCALING;
	DisplayStyle display_style = DS_OPAQUE;

	bool enable_keyboard_modifier_events = false;
	bool enable_key_auto_repeat_events = true;
	bool enable_all_mouse_move_events = false;

	QPoint topleft; // if panning

public:
	// the image which draws all contents:
	s_ptr<volatile Image> image;

public:
	explicit GTermWindow(QSize size = {1000,750}, QRgb bkg = 0xffffffff, ImageType = STATIC_IMAGE, ScalingMode = SM_SCALING, DisplayStyle = DS_OPAQUE);
	~GTermWindow() override = default;

	bool is_static() const noexcept { return dynamic_cast<volatile StaticImage*>(image.get()) != nullptr; }
	bool is_dynamic() const noexcept { return dynamic_cast<volatile DynamicImage*>(image.get()) != nullptr; }

	QSize windowSize() const noexcept { return size(); }
	QSize imageSize() const noexcept { return image->size(); }
	QRgb  backgroundColor() const noexcept { return image->background_color; }

	ScalingMode getScalingMode() const noexcept { return scaling_mode; }
	DisplayStyle getDisplayStyle() const noexcept { return display_style; }
	void setScalingMode(ScalingMode);
	void setDisplayStyle(DisplayStyle);
	void setBackgroundColor(QRgb);
	void resizeWindow(QSize);
	void resizeImage(QSize);

	void quit();
	void showFullscreen()	   { QOpenGLWindow::showFullScreen(); }
	void showNormalWindow()    { QOpenGLWindow::showNormal(); }
	void showMinimizedWindow() { QOpenGLWindow::showMinimized(); }
	void showMaximizedWindow() { QOpenGLWindow::showMaximized(); }

	NVPtr<Image> getImage() const noexcept { return nvptr(image); }
	NVPtr<StaticImage> getStaticImage() const noexcept { assert(is_static()); return nvptr(static_cast<volatile StaticImage*>(image.get())); }
	NVPtr<DynamicImage> getDynamicImage() const noexcept { assert(is_dynamic()); return nvptr(static_cast<volatile DynamicImage*>(image.get())); }

	void reset();			// reset & purge everything
	void erase() { getImage()->erase(); }
	void append(DrawingCommand&& cmd) { getDynamicImage()->append(std::move(cmd)); }
	void append(const DrawingCommand& cmd) { getDynamicImage()->append(cmd); }
	GTermWindow& operator<<(DrawingCommand&& cmd) { getDynamicImage()->append(std::move(cmd)); return *this; }
	GTermWindow& operator<<(const DrawingCommand& cmd) { getDynamicImage()->append(cmd); return *this; }

	void enableKeyboardModifierEvents(bool f) volatile noexcept { enable_keyboard_modifier_events = f; }
	void enableKeyAutoRepeatEvents(bool f) volatile noexcept { enable_key_auto_repeat_events = f; }
	void enableAllMouseMoveEvents(bool f) volatile noexcept { enable_all_mouse_move_events = f; }

	// Callbacks which can be set by client application:
	std::function<void(bool)> show_event = nullptr;
	std::function<void(bool)> focus_event = nullptr;
	std::function<void(const QSize& newwindowsize)> resize_event = nullptr;
	std::function<void(uint unicode, uint scancode, KeyModifiers)> key_down_event = nullptr;
	std::function<void(uint unicode, uint scancode, KeyModifiers)> key_up_event = nullptr;
	std::function<void(const QPoint&, uint button, uint newbuttons, uint modifiers, ulong timestamp_ms)> mouse_button_down_event = nullptr;
	std::function<void(const QPoint&, uint button, uint newbuttons, uint modifiers, ulong timestamp_ms)> mouse_button_up_event = nullptr;
	std::function<void(const QPoint&, uint buttons, uint modifiers)> mouse_move_event = nullptr;
	std::function<void()> frame_swapped_event = nullptr;

protected:
	virtual void keyPressEvent  (QKeyEvent*) override;
	virtual void keyReleaseEvent(QKeyEvent*) override;
	virtual void showEvent		(QShowEvent *) override;
	virtual void hideEvent		(QHideEvent *) override;
	virtual void focusInEvent	(QFocusEvent*) override;
	virtual void focusOutEvent	(QFocusEvent*) override;
	//virtual int heightForWidth (int w) const override;	// QWidget only
	virtual void mousePressEvent(QMouseEvent*) override;
	virtual void mouseReleaseEvent(QMouseEvent*) override;
	virtual void mouseMoveEvent (QMouseEvent*) override;
	virtual void resizeEvent    (QResizeEvent*) override;	// QOpenGLWindow::resizeEvent() calls resizeGL()
	virtual void paintEvent     (QPaintEvent*) override;	// QOpenGLWindow::paintEvent() calls paintGL()

	//virtual void initializeGL() override;
	//virtual void resizeGL(int,int) override;
	//virtual void paintGL() override;

signals:

public slots:

private:
	void call_key_event(std::function<void(uint unicode, uint scancode, KeyModifiers)> ,QKeyEvent*);
};

} // namespace



















