#ifndef SENSORREADER_H
#define SENSORREADER_H

#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>

#include "Recording.h"
#include "Sensors.h"

/**
 * parse all sensor values from HandyGames data-files
 */
class SensorReader {

private:

	static constexpr int bufSize = 4096;

public:

	/** parse all values within the given file */
	static Recording read(const std::string& file) {

		Recording rec;
		Sensors curSensor = Sensors::UNKNOWN;
		char buf[bufSize];

		// check
		std::ifstream f(file.c_str());
		if (!f.good()) {throw "error!";}

		// parse each line
		while(!f.bad() && !f.eof()) {

			// read the next line
			f.getline(buf, bufSize);
			std::string line(buf);

			// new sensor section? -> switch the current sensor
			if (startsWith(line, "// [SENSOR] ")) {
				std::string tmp = line.substr(19);
				int idx = indexOf(tmp, ";");
				curSensor = getSensor(tmp.substr(0, idx));
			}

			// skip empty lines
			else if (line.empty()) {;}

			// parse sensor values
			else {
				switch (curSensor) {
					case Sensors::TYPE_ACCELEROMETER:	parseAccel(rec, line); break;
					case Sensors::TYPE_GYROSCOPE:		parseGyro(rec, line); break;
					case Sensors::TYPE_MAGNETIC_FIELD:	parseMagField(rec, line); break;
					default:							break;
				}
			}


		}

		// done
		return rec;

	}

	static void parseAccel(Recording& rec, const std::string& line) {
		const std::vector<std::string> values = split(line);
		rec.accel.add(getTS(values[0]), SensorAccelerometer(getFloat(values[1]), getFloat(values[2]), getFloat(values[3])));
	}

	static void parseGyro(Recording& rec, const std::string& line) {
		const std::vector<std::string> values = split(line);
		rec.gyro.add(getTS(values[0]), SensorGyro(getFloat(values[1]), getFloat(values[2]), getFloat(values[3])));
	}

	static void parseMagField(Recording& rec, const std::string& line) {
		const std::vector<std::string> values = split(line);
		rec.magField.add(getTS(values[0]), SensorMagneticField(getFloat(values[1]), getFloat(values[2]), getFloat(values[3])));
	}



	/** get the timestamp for the given string-value */
	static uint64_t getTS(const std::string& s) {
		return std::stoul(s) / 1000 / 1000;
	}

	/** convert the given string to a float value */
	static float getFloat(const std::string& s) {
		return std::stof(s);
	}

	/** does the given haystack start with the given needle? */
	static bool startsWith(const std::string& haystack, const std::string& needle) {
		if (needle.length() > haystack.length()) {return false;}
		return memcmp(haystack.data(), needle.data(), needle.length()) == 0;
	}

	/** position of the first occurence of needle within haystack */
	static int indexOf(const std::string& haystack, const std::string& needle, const int start = 0) {
		std::string::size_type index = haystack.find(needle, start);
		return (index == std::string::npos ) ? (-1) : (index);
	}

	static std::vector<std::string> split(const std::string& str) {
		std::vector<std::string> list;
		int last = 0;
		while(true) {
			const int next = indexOf(str, ",", last);
			if (next == -1) {
				std::string sub = str.substr(last, str.length()-last-2);
				list.push_back(sub);
				break;
			} else {
				std::string sub = str.substr(last, next-last);
				list.push_back(sub);
				last = next+2;
			}
		}
		return list;
	}

};

#endif // SENSORREADER_H
