#pragma once
#include <string>
#include <vector>
#include <fstream>
#include <QPoint>
#include <map>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>

class RunData;

struct SolutionPointData {
	int round;
	int iteration;
	double objectiveFunction;
	int particleNumber;
	std::vector<bool> bitVec;
	std::string bitstringToStdString();
};
struct GraphDataPoint {
	double x;
	double y;
	SolutionPointData* orginalPoint;
	QColor color;
	GraphDataPoint() :x(0), y(0), orginalPoint(nullptr) {}
	GraphDataPoint(double x, double y, SolutionPointData* orginalPoint = nullptr);
	GraphDataPoint(double x, double y, QColor color, SolutionPointData* orginalPoint = nullptr);
	bool existLink() const;
	QPointF toQPointF() const;
	double squaredDistance(QPointF& graphPoint) const;
};

class SingleRun {
public:
	std::string name;
	std::string runDataName;
	const std::vector<SolutionPointData>::iterator begin;
	const std::vector<SolutionPointData>::iterator end;
	SingleRun(std::string uniqueName, const std::vector<SolutionPointData>::iterator begin, const std::vector<SolutionPointData>::iterator end, std::string name);
	std::vector<GraphDataPoint> bestMinSolutionFoundPerIteration;
	std::vector<GraphDataPoint> bestMaxSolutionFoundPerIteration;
	std::vector<GraphDataPoint> averageSolutionPerItertion;
	std::vector<GraphDataPoint> minSolutionPerItertion;
	std::vector<GraphDataPoint> maxSolutionPerItertion;
	std::vector<GraphDataPoint> dotsForDistribution;
	std::vector<GraphDataPoint> dotsForBitField;
	std::vector<GraphDataPoint> meanHammingDistancePerIteration;
	std::map<int, std::vector<GraphDataPoint>> particleMap;

	void calculateAdditionalData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits);
private:
	void calculateBestAndAverageIter();
	void calculateParticleSolution();
	void calculateDotsForDistribution();
	void calculateBitFieldData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits);
	void calculateMeanHammingDistance();
};



class RunData
{
public:
	std::string name;
	std::string information;
	std::string filePath;
	std::vector<SolutionPointData> solutionVec;
	std::list<SingleRun> singleRunList;
	std::vector<GraphDataPoint> bestAverageMaxSolutionFoundPerIteration;



	RunData();
	RunData(std::string filePath);

	void metalogFile(bool& retflag);

private:
	bool badFileFlag = false;
	std::fstream fileStream;
	int actualLine = 0;
	void getLine(std::string& bufferString);
	void calculateAverageOverRuns();
	
public:
	static int binominalIndex(const int n, int k);
	int static hammingdistance(std::vector<bool>& bitVecA, std::vector<bool>& bitVecB);
	double static meanHammingDistance(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end);
	static boost::multiprecision::cpp_int binominal(const int n, const int k);
	static boost::multiprecision::cpp_int positionInPermutation(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfSetBits);
	static boost::multiprecision::cpp_int positionInPermutation_reversed(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfUnsetBits);
};

