/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2023, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <mrpt/gui/CDisplayWindow.h>
#include <mrpt/gui/CDisplayWindow3D.h>
#include <mrpt/gui/CDisplayWindowPlots.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/system/CObserver.h>

#include <chrono>
#include <iostream>
#include <thread>

using namespace mrpt;
using namespace mrpt::gui;
using namespace mrpt::math;
using namespace mrpt::system;
using namespace mrpt::img;
using namespace std;

#include <mrpt/examples_config.h>
string myExampleImage(
	MRPT_EXAMPLES_BASE_DIRECTORY + string("img_basic_example/frame_color.jpg"));

class MyObserver : public mrpt::system::CObserver
{
   protected:
	void OnEvent(const mrptEvent& e) override
	{
		if (e.isOfType<mrptEventOnDestroy>())
			cout << "[MyObserver] Event received: mrptEventOnDestroy\n";
		else if (e.isOfType<mrptEventWindowResize>())
		{
			const mrptEventWindowResize& ee =
				static_cast<const mrptEventWindowResize&>(e);
			cout << "[MyObserver] Resize event received from: "
				 << ee.source_object << ", new size: " << ee.new_width << " x "
				 << ee.new_height << "\n";
		}
		else if (e.isOfType<mrptEventWindowChar>())
		{
			const mrptEventWindowChar& ee =
				static_cast<const mrptEventWindowChar&>(e);
			cout << "[MyObserver] Char event received from: "
				 << ee.source_object << ". Char code: " << ee.char_code
				 << " modif: " << ee.key_modifiers << "\n";
		}
		else if (e.isOfType<mrptEventWindowClosed>())
		{
			const mrptEventWindowClosed& ee =
				static_cast<const mrptEventWindowClosed&>(e);
			cout << "[MyObserver] Window closed event received from: "
				 << ee.source_object << "\n";
		}
		else if (e.isOfType<mrptEventMouseDown>())
		{
			const mrptEventMouseDown& ee =
				static_cast<const mrptEventMouseDown&>(e);
			cout << "[MyObserver] Mouse down event received from: "
				 << ee.source_object << "pt: " << ee.coords.x << ","
				 << ee.coords.y << "\n";
		}
		else
			cout << "[MyObserver] Event received: Another mrptEvent \n";
	}
};

// Observe windows for events.
// Declared out of the scope of windows so we can observe their destructors
MyObserver observer;

void TestGuiWindowsEvents()
{
	// Create some windows:
	CDisplayWindow win2D("Bitmap window", 300, 300);

	{
		mrpt::img::CImage img(300, 300, CH_RGB);
		img.filledRectangle(0, 0, 300, 300, TColor(0, 0, 255));
		img.textOut(50, 50, "Hello world!", TColor(255, 255, 255));
		win2D.showImage(img);
	}

	CDisplayWindow3D win3D("3D window", 300, 300);

	{
		mrpt::opengl::Scene::Ptr& scene = win3D.get3DSceneAndLock();
		scene->insert(mrpt::opengl::CGridPlaneXY::Create());
		win3D.unlockAccess3DScene();
		win3D.repaint();
	}

	CDisplayWindowPlots winPlot("Plots window", 300, 300);

	// Tile windows nicely:
	win2D.setPos(10, 10);
	win3D.setPos(340, 10);
	winPlot.setPos(10, 340);

	observer.observeBegin(win2D);
	observer.observeBegin(win3D);
	observer.observeBegin(winPlot);

	// Wait until end:
	cout << "Waiting for window events...\n";
	cout << "** Close any window to end the program **\n";

	while (win2D.isOpen() && win3D.isOpen() && winPlot.isOpen())
	{
		std::this_thread::sleep_for(100ms);
	}
}

// ------------------------------------------------------
//						MAIN
// ------------------------------------------------------
int main()
{
	try
	{
		TestGuiWindowsEvents();
		return 0;
	}
	catch (const std::exception& e)
	{
		std::cerr << "MRPT error: " << mrpt::exception_to_str(e) << std::endl;
		return -1;
	}
}
