#ifndef LEHELPER_H
#define LEHELPER_H

#include <fstream>
#include <Indoor/geo/EarthPos.h>
#include <Indoor/sensors/radio/setup/WiFiFingerprints.h>
#include <Indoor/floorplan/v2/Floorplan.h>

#include "plots/Plotty.h"

class LeHelper {

public:

	static void writeGoogleLine(std::vector<EarthPos>& poss) {
		const std::string file = "/apps/android/workspace/OTHER2017/osm/googleLine.js";
		std::ofstream out(file);
		out << "function getLines() {return [\n";
		out.precision(15);

		for (const EarthPos& pos : poss) {
			out << "\t{" << "lat:" << pos.lat << ", lng:" << pos.lon << "},\n";
		}

		out << "];}";
		out.flush();
		out.close();

	}

	static inline bool isOutdoor(const WiFiFingerprint& fp) {

		const Point3 pos = fp.pos_m;

		// garden
		if (pos == Point3(21, 12, 1.3)) {return true;}
		if (pos == Point3(21, 27, 1.3)) {return true;}
		if (pos == Point3(39, 12, 1.3)) {return true;}
		if (pos == Point3(39, 27, 1.3)) {return true;}
		if (pos == Point3(67, 12, 1.3)) {return true;}
		if (pos == Point3(67, 27, 1.3)) {return true;}
		if (pos == Point3(88, 12, 1.3)) {return true;}
		if (pos == Point3(88, 27, 1.3)) {return true;}

		// front door
		if (pos == Point3(94, 43, 4+1.3)) {return true;}
		if (pos == Point3(110, 43, 4+1.3)) {return true;}
		if (pos == Point3(94, 55, 4+1.3)) {return true;}
		if (pos == Point3(110, 55, 4+1.3)) {return true;}
		if (pos == Point3(67.2, 55, 4+1.3)) {return true;}

		return false;

	}

	static inline bool isStaircase(const WiFiFingerprint& fp) {

		const Point3 pos = fp.pos_m;

		// floor 0
		if (pos == Point3(67.2, 48.5, 1.3)) {return true;}
		if (pos == Point3(11.2, 48.3, 1.3)) {return true;}
		if (pos == Point3(16.5, 11.9, 1.3)) {return true;}
		if (pos == Point3(57.4,  2.6, 1.3)) {return true;}
		if (pos == Point3(57.4, -3.2, 3.0)) {return true;}

		// floor 1
		if (pos == Point3(67.2, 48.3, 4+1.3)) {return true;}
		if (pos == Point3(11.4, 48.3, 4+1.3)) {return true;}
		if (pos == Point3(16.1, 11.9, 4+1.3)) {return true;}
		if (pos == Point3(57.4,  2.4, 4+1.3)) {return true;}

		// floor 2
		if (pos == Point3(67.0, 48.5, 3.4+4+1.3)) {return true;}
		if (pos == Point3(11.6, 48.5, 3.4+4+1.3)) {return true;}
		if (pos == Point3(16.3, 11.9, 3.4+4+1.3)) {return true;}

		// floor 3
		if (pos == Point3(67.0, 48.3, 3.4+3.4+4+1.3)) {return true;}
		if (pos == Point3(11.4, 48.5, 3.4+3.4+4+1.3)) {return true;}
		if (pos == Point3(16.3, 11.9, 3.4+3.4+4+1.3)) {return true;}

		return false;

	}

	/** remove all outdoor fingerprints */
	static WiFiFingerprints removeOutdoor(const WiFiFingerprints& inp) {

		WiFiFingerprints res;

		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			if (isOutdoor(fp)) {continue;}
			res.add(fp);
		}

		return res;

	}

	static WiFiFingerprints removeStaircases(const WiFiFingerprints& inp) {

		WiFiFingerprints res;

		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			if (isStaircase(fp)) {continue;}
			res.add(fp);
		}

		return res;
	}

	static WiFiFingerprints removeIndoor(const WiFiFingerprints& inp) {

		WiFiFingerprints res;

		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			if (!isStaircase(fp) && !isOutdoor(fp)) {continue;}
			res.add(fp);
		}

		return res;
	}


	static WiFiFingerprints removeIf(const WiFiFingerprints& inp, std::function<bool(const WiFiFingerprint&)> remove) {

		WiFiFingerprints res;

		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			if (remove(fp)) {continue;}
			res.add(fp);
		}

		return res;
	}


	static WiFiFingerprints onlyOutdoor(const WiFiFingerprints& inp) {

		WiFiFingerprints res;

		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			if (!isOutdoor(fp)) {continue;}
			res.add(fp);
		}

		return res;

	}

	static void writeCode(const std::string& file, const std::string& code) {
		std::ofstream out(file);
		out << code;
		out.close();
	}

	static void plot(const Floorplan::IndoorMap* map, const WiFiFingerprints& inp, const std::string& title = "Fingerprints") {

		Plotty* p = new Plotty(map);
		p->setTitle(title);
		p->buildFloorplan();
		p->cpoints.clear();
		for (const WiFiFingerprint& fp : inp.getFingerprints()) {
			const K::GnuplotPoint3 gp(fp.pos_m.x, fp.pos_m.y, fp.pos_m.z);
			//p->cpoints.add(gp, 1);
			const float size = fp.measurements.entries.size() / 10.0 * 1.0;
			p->addFloorRect(fp.pos_m, size, Color::fromRGB(255,0,0));
			p->addLabel(std::to_string(fp.measurements.entries.size()), fp.pos_m+Point3(1,1,1));
		}
		p->plot();

	}

	/** is the given mac one of a FHWS ap? */
	static inline bool isFHWS_AP(const MACAddress& mac) {
		return mac.asString().substr(0,5) == "D8:84";
	}

	/** remove all non-FHWS APs from the calibration */
	static inline void removeNonFHWS(WiFiFingerprints& calib) {
		int removed = 0;
		for (WiFiFingerprint& fp : calib.getFingerprints()) {
			for (size_t i = 0; i < fp.measurements.entries.size(); ++i) {
				const WiFiMeasurement& m = fp.measurements.entries[i];
				if (!isFHWS_AP(m.getAP().getMAC())) {
					fp.measurements.entries.erase(fp.measurements.entries.begin() + i);
					--i;
					++removed;
				}
			}
		}
		std::cout << "removed " << removed << " entries" <<std::endl;
	}


};

#endif // HELPER_H
