#ifndef PAPERPLOT2D_H
#define PAPERPLOT2D_H

#include <KLib/misc/gnuplot/Gnuplot.h>

#include <KLib/misc/gnuplot/GnuplotPlot.h>
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
#include <KLib/misc/gnuplot/GnuplotPlotElementColorPoints.h>

#include <Indoor/floorplan/Floor.h>
#include <Indoor/geo/Length.h>

class PaperPlot2D {

public:

	struct Size {
		float w;
		float h;
		Size(const float w, const float h) : w(w), h(h) {;}
	};

public:

	K::Gnuplot gp;
	K::GnuplotPlot plot;

	K::GnuplotPlotElementLines floors;
	K::GnuplotPlotElementColorPoints nodes;

	std::string file;

public:

	PaperPlot2D(const std::string& file, Size s) : file(file) {
		toFile(file, s);
		setup();
	}

	PaperPlot2D() {
		setup();
	}

private:

	void setup() {

		floors.setLineWidth(1.5);

		nodes.setPointType(7);

		plot.add(&nodes);
		plot.add(&floors);

		gp << "unset border\n";
		gp << "unset colorbox\n";

		gp << "set tics scale 0,0\n";		// HACK! "unset tics\n" segfaults current gnuplot version...
		gp << "set format x ' '\n";
		gp << "set format y ' '\n";

		gp << "set size ratio -1\n";

	}


	void toFile(const std::string& file, const Size s) {
		gp << "set output '" << file << "'\n";
		gp << "set terminal eps size " << s.w << "," << s.h << "\n";
	}

public:

	void setRanges(const float x1, const float x2, const float y1, const float y2) {
		gp << "set xrange [" << x1 << ":" << x2 << "]\n";
		gp << "set yrange [" << y1 << ":" << y2 << "]\n";
	}

	void show() {
		gp.draw(plot);
		if (file.length() != 0) {
			std::string dataFile = file + ".dat";
			std::ofstream os(dataFile.c_str());
			os << gp.getBuffer();
			os.close();
		}
		gp.flush();
	}

	/** add all obstacles of the given floor to the provided height */
	void addFloor(const Floor& f) {

		// add each wall
		for (const Line2& l : f.getObstacles()) {
			const K::GnuplotPoint2 p1(l.p1.x, l.p1.y);
			const K::GnuplotPoint2 p2(l.p2.x, l.p2.y);
			floors.addSegment(p1, p2);
		}

	}


//	void removeGrid() {
//		gp << "unset object\n";
//	}

	/** add the grid to the plot */
	template <typename T, typename Colorizer> void addGrid(Grid<T>& grid, const Colorizer col) {

		// get the min/max value
		float max = -999999;
		float min = +999999;
		for (const T& n1 : grid) {
			const float val = col.get(n1);
			//const float val = n1.distToTarget;
			if (val > max) {max = val;}
			if (val < min) {min = val;}
		}
		gp << "set cbrange["<<min<<":"<<max<<"]\n";

//		for (const T& n1 : grid) {
//			const K::GnuplotPoint2 p1(n1.x_cm, n1.y_cm);
//			const float color = n1.imp;
//			//const float color = n1.distToTarget/max;
//			//const float color = 0;
//			nodes.add(p1, color);
//		}

		int i = 0;
		for (const T& n1 : grid) {
			if (col.skip(n1)) {continue;}
			gp << "set object " << (++i) << " rectangle center " << n1.x_cm << "," << n1.y_cm << " size 20,20 fs solid noborder fc palette cb " << col.get(n1) << "\n";
		}

	}


};


#endif // PAPERPLOT2D_H
