#ifndef TRAINDATA_H
#define TRAINDATA_H

#include "Settings.h"
#include <KLib/fs/File.h>
#include "../Interpolator.h"
#include "../sensors/SensorReader.h"

struct ClassifiedPattern {
	std::string className;
	std::vector<float> pattern;
	ClassifiedPattern(const std::string& className, const std::vector<float>& pattern) : className(className), pattern(pattern) {;}
};

struct ClassifiedFeature {
	std::string className;
	std::vector<float> feature;
	ClassifiedFeature(const std::string& className, const std::vector<float>& feature) : className(className), feature(feature) {;}
	ClassifiedFeature() : className("??????") {;}

	/** get the l2- distance to the given vector */
	float getDistance(const std::vector<float>& vec) const {
		if (vec.size() != feature.size()) {throw "error!";}
		float dist = 0;
		for (int i = 0; i < (int)vec.size(); ++i) {dist += (vec[i]-feature[i])*(vec[i]-feature[i]);}
		return std::sqrt(dist);
	}

};

struct ClassifiedDataFile {
	std::string className;
	std::string fileName;
	ClassifiedDataFile(const std::string& className, const std::string& fileName) : className(className), fileName(fileName) {;}
};

class Data {

public:

	/** get X data-files for each class */
	static std::vector<ClassifiedDataFile> getDataFiles(const int filesPerClass) {

		Settings s;
		std::vector<ClassifiedDataFile> files;

		K::File folder(s.path);
		for (const std::string& className : s.classNames) {
			K::File classFolder(folder, className);

			int i = 0;
			for (const K::File classFile : classFolder.listFiles()) {
				const std::string fileName = classFile.getAbsolutePath();
				if (fileName[fileName.length()-1] == 'm') {continue;}
				if (++i > filesPerClass) {break;}
				ClassifiedDataFile cdf(className, fileName);
				files.push_back(cdf);
			}

		}

		return files;

	}

	/** get sample date from the given data-file */
	static std::vector<std::vector<float>> getSamples(const std::string fileName, const int windowSize_ms, const int regionStart_ms, const float regionPercent, const int stepSize_ms) {

		// read all sensor-values within the given data-file
		Recording rec = SensorReader::read(fileName);

		// get the value-interpolator
		K::Interpolator<uint64_t, SensorAccelerometer> intAccel;
		for (const auto& val : rec.accel.values) {intAccel.add(val.ts, val.val);}
		intAccel.makeRelative();

		const int regionEnd_ms = intAccel.values.back().key * regionPercent;



		// construct all sample windows
		std::vector<std::vector<float>> samples;
		for (int center = regionStart_ms; center < regionEnd_ms; center += stepSize_ms) {
			std::vector<float> window = getSampleWindow(intAccel, center, windowSize_ms, stepSize_ms);
			samples.push_back(window);
		}

		return samples;

	}

	template <typename T> static std::vector<float> getSampleWindow(K::Interpolator<uint64_t, T>& interpol, const int center_ms, const int windowSize_ms, const int stepSize_ms) {

		std::vector<float> window;
		const int start = center_ms - windowSize_ms/2;
		const int end = center_ms + windowSize_ms/2;

		for (uint64_t ms = start; ms < end; ms += stepSize_ms) {
			const T val = interpol.get(ms);
			window.push_back(val.x);
			window.push_back(val.y);
			window.push_back(val.z);
		}

		return window;

	}

};

#endif // TRAINDATA_H

