#include "pch.h"
#include "tsneIteractive.h"
#include <QDebug>
#include <thread>
#include <future>
#include <chrono>

#include "src/t_sne/tsne.h"

tsneIteractive::tsneIteractive(QWidget *parent)
	: QWidget(parent), view(new GraphView(this, Bound(-50,50,-50,50))), gradient(new ColorGradient(this)), timer(new QTimer)
{
	ui.setupUi(this);
	ui.verticalLayout->insertWidget(0, view);
	view->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
	ui.verticalLayout->addWidget(gradient);
	//ui.gridLayout->addWidget(gradient, 4, 0);
	//ui.gridLayout->addWidget(gradient, 4, 0, 1, 4);
	view->setUseFixedBound(true);
	connect(timer, &QTimer::timeout, this, static_cast<void (tsneIteractive::*)()>(&tsneIteractive::updateCanvasIfAlgoRuns));
	connect(ui.startButton, &QPushButton::pressed,
		this, &tsneIteractive::startRun);
	connect(gradient, &ColorGradient::gradientChanged, this, &tsneIteractive::updateViewGradient);
	
}

tsneIteractive::~tsneIteractive()
{
	//hTsne.get();
}

void tsneIteractive::assignRunData(RunData* data)
{
	this->data = data;
}

void tsneIteractive::updateCanvasIfAlgoRuns()
{
	if (hTsne.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
		hTsne.get();
		timer->stop();
	}
	//view->autoZoomOut();
	view->update();
}

void tsneIteractive::updateViewGradient()
{
	qDebug() << "tsneIteractive::updateViewGradient()";
	view->updateGraphColors(*gradient);
	update();
}

void tsneIteractive::startRun()
{
	if (data == nullptr) {
		qDebug() << "NoData!";
		return;
	}
	qDebug() << "Start run!";
	//Erstelle Y:
	//N -> amount of dataPoints 
	//D -> Dimension of DataPoints
	size_t N = data->solutionVec.size(), D = data->solutionVec[0].bitVec.size();
	qDebug() << "N:" << N << " D:" << D;
	double* X = new double[N * D];

	int nD = 0;
	for (int n = 0; n < N; n++) {
		const SolutionPointData& sol = data->solutionVec[n];
		for (int d = 0; d < D; d++) {
			X[nD + d] = sol.bitVec[d] ? 1.0 : 0.0;
		}
		nD += D;
	}
	//no_dims -> dimension of target 
	size_t no_dims = 2;
	//double* Y = new double[N * no_dims];
	double* Y = (double*)calloc(N * no_dims,  sizeof(double));
	view->addYMatrix(Y, N, data->solutionVec);
	view->updateGraphColors(*gradient);
	view->update();
	//Perplexity and theta
	double perplexity = 20;
	double theta = 0;
	//learnig rate epsillon;
	double eta = 200;
	//Random 
	int rand_seed = 17235761;
	bool skip_random_init = false;
	//Iter changes
	int max_iter = 700, stop_lying_iter = 120, mom_switch_iter = 20;
	hTsne = std::async(std::launch::async, TSNE::run, X, N, D, Y, no_dims, perplexity, theta, eta, rand_seed, skip_random_init, max_iter, stop_lying_iter, mom_switch_iter);
	timer->start(34);
	std::cout << "Finished:" << std::endl;
}
