#include "pch.h"
#include "TsnePlott.h"
#include <limits>
TsnePlott::TsnePlott(QWidget *parent)
	: SearchSpacePlott(parent)
{
	setAxisLegend("X Axis", "Y Axis");
}

TsnePlott::~TsnePlott()
{
}

void TsnePlott::assignMatrix(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, double* yMatrixFromTsneAlgo, int n, ColorGradient& gradient)
{
	this->begin = begin;
	this->end = end;
	this->yMatrixFromTsneAlgo = yMatrixFromTsneAlgo;
	this->N = n;
	updateColors(gradient);
	
}

void TsnePlott::clear()
{
	begin = end = std::vector<SolutionPointData>::iterator();
	yMatrixFromTsneAlgo = nullptr;
	N = 0;
	colorPointDataVec.clear();
	update();
}

void TsnePlott::updateColors(ColorGradient& gradient)
{
	colorPointDataVec.clear();
	for (auto iterator = begin; iterator != end; iterator++) {
		colorPointDataVec.push_back(gradient.getColorFromValue(iterator->objectiveFunction));
	}
	update();
}

void TsnePlott::frameGraphInView()
{
	if (begin == end || !yMatrixFromTsneAlgo) {
		return;
	}
	VisibleWindow nextWindow(0,0,0,0);
	QPointF first(yMatrixFromTsneAlgo[0], yMatrixFromTsneAlgo[1]);
	nextWindow.xMin = nextWindow.xMax = first.x();
	nextWindow.yMin = nextWindow.yMax = first.y();


	for (int i = 1; i < this->N; i++) {
		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
		if (point.x() < nextWindow.xMin) {
			nextWindow.xMin = point.x();
		}
		else if (point.x() > nextWindow.xMax) {
			nextWindow.xMax = point.x();
		}
		if (point.y() < nextWindow.yMin) {
			nextWindow.yMin = point.y();
		}
		else if (point.y() > nextWindow.yMax) {
			nextWindow.yMax = point.y();
		}
	}
	nextWindow.ZoomOut(0.05);
	if (std::abs(nextWindow.xMax - nextWindow.xMin) > std::numeric_limits<double>::min()) {
		window.xMin = nextWindow.xMin;
		window.xMax = nextWindow.xMax;
	}
	if (std::abs(nextWindow.yMax - nextWindow.yMin) > std::numeric_limits<double>::min()) {
		window.yMin = nextWindow.yMin;
		window.yMax = nextWindow.yMax;
	}
	update();
}

void TsnePlott::searchForPointUnderCursor()
{
	//check if mouse stayed still
	QPoint globalPosition = QCursor::pos();
	QPointF pos = this->mapFromGlobal(globalPosition);

	if (pos != lastPosition) {
		return;
	}
	if (begin == end || !yMatrixFromTsneAlgo) {
		return;
	}
	QRect graphDisplayRect = getDisplayRect();
	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
	
	QPointF minPoint = transformGraphToView(QPointF(yMatrixFromTsneAlgo[0], yMatrixFromTsneAlgo[1]));
	std::vector<SolutionPointData>::iterator minData = begin;
	double minSqaredDistance = sqaredDistance(transformGraphToView(minPoint, stregth_factorX, stregth_factorY, translation), pos);
	auto iter = begin;
	for (int i = 1; i < this->N; i++, iter++) {
		if (iter->iteration < minIter) {
			continue;
		}
		if (iter->iteration > maxIter) {
			break;
		}
		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
		double distance = sqaredDistance(transformGraphToView(point, stregth_factorX, stregth_factorY, translation), pos);
		if (distance < minSqaredDistance) {
			minSqaredDistance = distance;
			minPoint = point;
			minData = iter;
		}
	}

	//if curser is radius + 3pixel away
	if (minSqaredDistance <= circleSize * circleSize + 9) {
		QPointF pointInWidget = transformGraphToView(minPoint, stregth_factorX, stregth_factorY, translation);
		QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), QString::fromStdString(minData->bitstringToStdString()));
	}
}

void TsnePlott::addPointsInWindowToScratchPad(VisibleWindow& window)
{
	if (!pad) {
		qDebug() << "NoPad";
		return;
	}
	if (begin == end || !yMatrixFromTsneAlgo) {
		return;
	}
	auto iter = begin;
	for (int i = 1; i < this->N; i++, iter++) {
		if (iter->iteration < minIter) {
			continue;
		}
		if (iter->iteration > maxIter) {
			break;
		}
		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
		if (window.inBound(point)) {
			pad->addPoint(*iter);
		}
	}
}

void TsnePlott::drawData(QPainter& painter)
{
	if (begin == end || !yMatrixFromTsneAlgo) {
		return;
	}
	QRect graphDisplayRect = getDisplayRect();
	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
	auto iter = begin;
	painter.setPen(Qt::transparent);
	for (int i = 0; i < this->N; i++, iter++) {
		if (iter->iteration < minIter) {
			continue;
		}
		if (iter->iteration > maxIter) {
			break;
		}
		QColor color = colorPointDataVec[i];
		color.setAlphaF(this->transparentAlphaValue);
		painter.setBrush(color);
		painter.drawEllipse(transformGraphToView(QPointF(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]), stregth_factorX, stregth_factorY, translation), circleSize, circleSize);
	}
	painter.setBrush(Qt::BrushStyle::NoBrush);
}
