/* +------------------------------------------------------------------------+
   |                     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          |
   +------------------------------------------------------------------------+ */
#pragma once

#include <mrpt/gui/CDisplayWindow3D.h>
#include <mrpt/system/COutputLogger.h>

#include "CWindowObserver.h"

namespace mrpt::graphslam
{
/**\brief Class acts as a container for storing pointers to
 * mrpt::gui::CDisplayWindow3D,
 * mrpt::graphslam::CWindowObserver instances.
 *
 * CWindowManager also provides methods for adding/positioning textMessages
 * and viewports in the CDisplayWindow in a compact and consistent way.
 *
 * \ingroup mrpt_graphslam_grp
 */
class CWindowManager : public mrpt::system::COutputLogger
{
   public:
	/**\brief Default class constructor */
	CWindowManager() { this->initCWindowManager(); }
	/**\brief Class constructor*/
	CWindowManager(mrpt::gui::CDisplayWindow3D* win_in)
	{
		this->initCWindowManager();
		this->setCDisplayWindow3DPtr(win_in);
	}
	/**\brief Class constructor*/
	CWindowManager(
		mrpt::gui::CDisplayWindow3D* win_in,
		mrpt::graphslam::CWindowObserver* observer_in)
	{
		this->initCWindowManager();

		this->setWindowObserverPtr(observer_in);
		this->setCDisplayWindow3DPtr(win_in);
	}
	/**\brief Class destructor. */
	~CWindowManager() override = default;
	/**\brief Store the CDisplayWindow3D pointer in the CWindowManager
	 * instance.
	 *
	 * \sa setWindowObserverPtr
	 */
	void setCDisplayWindow3DPtr(mrpt::gui::CDisplayWindow3D* win_in)
	{
		m_fetched_displaywindow_pointer = true;
		win = win_in;

		MRPT_LOG_DEBUG_STREAM("Fetched the CDisplayWindow3D* successfully");
	}
	/**\brief Store the CWindowObserver pointer in the CWindowManager instance.
	 *
	 * \sa setCDisplayWindow3DPtr
	 */
	void setWindowObserverPtr(mrpt::graphslam::CWindowObserver* obsever_in)
	{
		m_fetched_observer_pointer = true;
		observer = obsever_in;

		MRPT_LOG_DEBUG_STREAM("Fetched the CWindowObserver* successfully");
	}

	/**\brief Assign the next available offset_y and text_index for the
	 * textMessage under construction.
	 *
	 * Used for consistent positioning of textMessages in the
	 * CDisplayWindow3D.
	 *
	 * \sa assignViewPortParameters
	 */
	void assignTextMessageParameters(double* offset_y, int* text_index)
	{
		*offset_y = m_curr_offset_y;
		m_curr_offset_y += m_offset_y_step;

		*text_index = m_curr_text_index;
		m_curr_text_index += m_index_text_step;
	}

	/**\brief Wrapper call around the CWindowDisplay3D */
	bool isOpen()
	{
		if (win) { return win->isOpen(); }
		else
		{
			return false;
		}
	}

	/**\brief Wrapper around the CDisplayWindow3D::addTextMessage method, so
	 * that the
	 * user does not have to specify the font name and size.
	 *
	 * \note see initCWindowManager method for the default fontName and
	 * fontSize used.
	 */
	void addTextMessage(
		const double x, const double y, const std::string& text,
		const mrpt::img::TColorf& color = mrpt::img::TColorf(1.0, 1.0, 1.0),
		const size_t unique_index = 0)
	{
		if (!win) { return; }

		win->addTextMessage(x, y, text, unique_index);
	}

	/**\brief Assign position and size values for the placement of the next
	 * viewport
	 *
	 * Used for consistent positioning of the Viewports in the CDisplayWindow3D
	 *
	 * \sa assignTextMessageParameters
	 */
	void assignViewportParameters(
		double* x, double* y, double* width, double* height)
	{
		*x = m_viewp_x;
		*y = m_viewp_y;

		*width = m_viewp_width;
		*height = m_viewp_height;

		m_viewp_y -= m_viewp_height + m_viewp_margin;
	}

	mrpt::gui::CDisplayWindow3D* win; /**< CDisplayWindow instance */
	mrpt::graphslam::CWindowObserver* observer; /**< CWindowObserver instance */
   private:
	/**\brief Initialization method, to be called from the various Constructors.
	 */
	void initCWindowManager()
	{
		m_fetched_displaywindow_pointer = false;
		m_fetched_observer_pointer = false;
		win = nullptr;
		observer = nullptr;

		m_offset_y_step = 20.0;
		m_index_text_step = 1;
		m_font_name = "sans";
		m_font_size = 12;
		m_curr_offset_y = 30;
		m_curr_text_index = 1;

		m_viewp_width = 0.2;
		m_viewp_height = 0.2;
		m_viewp_x = 0.75;
		m_viewp_margin = 0.01;
		m_viewp_y = 0.72;

		// loger related directives
		this->setLoggerName("CWindowManager");
	}

	bool m_fetched_observer_pointer;
	bool m_fetched_displaywindow_pointer;

	double m_offset_y_step;
	int m_index_text_step;
	double m_curr_offset_y;
	int m_curr_text_index;

	std::string m_font_name;
	int m_font_size;

	// viewports configuration
	double m_viewp_width;
	double m_viewp_height;
	double m_viewp_x;
	double m_viewp_y; /**< vertical layout of the viewports */
	double m_viewp_margin;
};
}  // namespace mrpt::graphslam
