#pragma once
#include <QWidget>
#include <QPaintEvent>
#include <QAbstractListModel>
#include <QPen>
#include <QPainter>
#include <vector>
#include "RunData.h"
#include "ColorGradient.h"

class GraphView;
class RunData;
struct SolutionPointData;




struct GraphSeries {
	std::vector<GraphDataPoint>* data;
	double minX, maxX;
	double minY, maxY;
	RunData* run;



	//Settings for visual
	QString name;
	QColor color;
	int lineWidth = 2;
	double circleRadius = 2.0;
	enum class SeriesType{ Line, Dot, LineDot};
	bool useDataPointColor = false;
	SeriesType type;
	bool hide = false;
};

struct Bound {
	double minX = 0, minY = 0, maxX = 0, maxY = 0;
	enum class Change{MoveLeft, MoveRight, MoveUp, MoveDown, ZoomOut, ZoomIn, ZoomInX, ZoomInY, ZoomOutX, ZoomOutY, Reset};
	Bound() {}
	Bound(double minX, double maxX, double minY, double maxY):minX(minX), maxX(maxX), minY(minY), maxY(maxY){}
	void move(GraphView* widget,const Change& type, const double changePercentage = 0.1);
	void move(GraphView* widget, QPointF& delta, double realPixelWidthX, double realPixelWidthY);
	void move(GraphView* widget, QPointF& targetPoint);
};

class GraphView :public QWidget
{
	Q_OBJECT

public:
	GraphView(QWidget* parent, Bound fixedBound = Bound());
	~GraphView();
	QString title;
	Bound fixedBound;
	//TODO: make fancy
	bool useInterval = false;
	int maxIter = 0;
	int minIter = 0;
	std::vector<GraphSeries> graphSeriesVec;

private:
	bool useFixedBound;
	//Data
	Bound totalBound;
	Bound actualBound = totalBound;
	bool drawTotalBound = false;
	double rangeGraphX = 0, rangeGraphY = 0;

	double* yArray = nullptr;
	QColor* pointColors = nullptr;
	std::vector<SolutionPointData>* solVec = nullptr;
	int yDoubleDoubleValuesAmount = 0;
	



	//Visualization
	QString xAxisNumbers[11];
	QString yAxisNumbers[11];
	double hueoffset;
	QPen linePen, rectPen, axisPen;
	GraphSeries* highlightSeries = nullptr;
	//Control
	QPointF oldPositionForMouseEvent;
	QPointF mousePressedValue;
	bool mousePressed = false;



public:
	void setUseFixedBound(bool value);
	void generateAndAddRandomLine();
	void addLine(std::vector<GraphDataPoint>* line, RunData* run);
	void addLine(std::vector<GraphDataPoint>* line, RunData* run, QColor color);
	void addDots(std::vector<GraphDataPoint>* dots, RunData* run);
	void addDots(std::vector<GraphDataPoint>* dots, RunData* run, QColor color);
	void removeAllSeriesWithRundata(RunData* run);
	void removeAllSeries();
	void reset();
	void calculateRangeXY();
	void generateAxisNumberStrings();
	void update();
	void setDrawBound(bool value);
	QColor generateNextColorForGraph();
	void resetBound();
	void addYMatrix(double* yArray, std::vector<SolutionPointData>& solVec);
	void autoZoomOut();
	void updateGraphColors(ColorGradient& gradient);





private:
	void calculateTotalMatrixBound();
	void calculateTotalGraphBound();
	void GraphView::calculateMinMaxXY(GraphSeries& lgs);
	void addSeries(std::vector<GraphDataPoint>* line, RunData* run, QColor color, GraphSeries::SeriesType type);
	QPointF transformGraphToView(QPointF& graphpoint, double stregth_factorX, double stregth_factorY, QPointF& translation) const;
	QPointF transformViewToGraph(QPointF& viewpoint) const;
	GraphDataPoint findNearestGraphDataPointFromGraphCoordinate(QPointF& graphpoint);
	GraphDataPoint findNearestGraphDataPointFromViewCordinate(QPointF& viewpoint);
	bool inBoundX(QPointF& point);
	bool inBoundY(QPointF& point);
	bool inBound(QPointF& point);

	//overrides
	void keyPressEvent(QKeyEvent* event) override;
	void wheelEvent(QWheelEvent* event) override;
	void mouseMoveEvent(QMouseEvent* event) override;
	void mousePressEvent(QMouseEvent* event) override;
	void mouseReleaseEvent(QMouseEvent* event) override;
	void paintEvent(QPaintEvent* event) override;
public slots:
	void setMaxIter(int value);
	void setMinIter(int value);
};

