#ifndef MAPVIEW2D_H
#define MAPVIEW2D_H

#include "../misc/fixc11.h"

#include <QWidget>

#include "Scaler2D.h"
#include "Path2D.h"
#include "Renderable2D.h"

#include <Indoor/nav/dijkstra/DijkstraPath.h>
#include <Indoor/geo/Point3.h>

namespace Floorplan {
	class IndoorMap;
}

template <typename T> class Grid;
class MyGridNode;
class Renderable2D;
class QSlider;
class QPushButton;
class QGestureEvent;
class ColorPoints2D;
class Path2D;

template <typename T> class DijkstraPath;
namespace K {
	template <typename T> class Particle;
}
class MyState;

class WiFiCalibTool;
class WiFiCalibrationDataModel;

class MapView2D : public QWidget {

	Q_OBJECT

private:

	std::vector<Renderable2D*> elementsA;
	std::vector<Renderable2D*> elementsB;

	ColorPoints2D* colorPoints = nullptr;
	Path2D* pathToDest = nullptr;
	Path2D* pathWalked = nullptr;
	WiFiCalibTool* wifiCalib = nullptr;

	Scaler2D scaler;
	RenderParams2D renderParams;
	float layerHeight_m = 0;

	struct Move {
		Point2 startCenter_px;
		Point2 startMouse_px;
	} move;

	QWidget* menu = nullptr;
	QSlider* sldLayer = nullptr;
	QPushButton* btnColorPoints = nullptr;
	QPushButton* btnLayerPlus = nullptr;
	QPushButton* btnLayerMinus = nullptr;

public:

	explicit MapView2D(QWidget *parent = 0);

	/** set the to-be-shown map */
	void setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map);

	/** show importance factors for the grid */
	void showGridImportance(Grid<MyGridNode>* grid);

	/** set the height-slice to be visible */
	void setRenderHeight(const float height_m);



	/** set the path to the destination MUST BE CALLED FROM THE MAIN THREAD */
	void setPathToDestination(const std::vector<Point3>& path);

	/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD */
	template <typename Node> void setPathToDestination(const DijkstraPath<Node>* path) {this->pathToDest->set(*path);}

	/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD*/
	Q_INVOKABLE void setPathToDestination(const void* path) { setPathToDestination( (const DijkstraPath<MyGridNode>*) path); }



	/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
	void setPathWalked(const std::vector<Point3>& path) {this->pathWalked->set(path);}

	/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
	Q_INVOKABLE void setPathWalked(const void* path) { this->pathWalked->set( *((const std::vector<Point3>*) path)); }



	/** NOTE: must be called from Qt's main thread! */
	Q_INVOKABLE void showParticles(const void* particles) {
		showParticles((const std::vector<K::Particle<MyState>>*) particles);
	}

	/** NOTE: must be called from Qt's main thread! */
	void showParticles(const std::vector<K::Particle<MyState>>* particles);



	/** set the currently estimated position */
	void setCurrentEstimation(const Point3 pos, const Point3 dir);


signals:

protected slots:

	void onLayerSelect();
	void onLayerPlus();
	void onLayerMinus();

public slots:

	void resizeEvent(QResizeEvent*);

	void paintEvent(QPaintEvent*);

	void mousePressEvent(QMouseEvent*);
	void mouseMoveEvent(QMouseEvent*);
	void mouseReleaseEvent(QMouseEvent*);
	void wheelEvent(QWheelEvent*);

	bool event(QEvent*);
	bool gestureEvent(QGestureEvent *event);

};

#endif // MAPVIEW2D_H
