#include "pch.h"
#include "metavis.h"
#include "SettingDialog.h"
#include <QStandardPaths>
#include <QDockwidget>
#include <QLabel>
#include <QLayout>
#include <QDebug>
#include <QStyleFactory>
#include <QtWebChannel/QtWebChannel>
#include <QtWebEngineWidgets/QWebEngineView>
#include <QFileDialog>
#include <QDir>
#include <map>
#include <boost/multiprecision/cpp_int.hpp>
#include <QDesktopWidget>
#include <QSlider>
#include <QSizePolicy>
#include "DockableGraphView.h"
#include "ProjectManager.h"
#include "RangeSlider.h"
#include "tsneIteractive.h"
#include "util.h"



metavis::metavis(QWidget* parent)
	: QMainWindow(parent), actualBestAverageGraph(createCustomWidget("Best vs Avg")), actualParticleGraph(createCustomWidget("Particle", true)), actualMinMaxGraph(createCustomWidget("MinMaxGraph", true)), actualMeanHmmingDistanceGraph(createCustomWidget("MeanHammingDistance", true)),
	multiBestGraph(createCustomWidget("All Runs: Best")), multiAvgGraph(createCustomWidget("All Runs: Avg", true)), multiMinGraph(createCustomWidget("All Runs: Min", true)), multiMaxGraph(createCustomWidget("All Runs: Max", true)), multiMeanHammingDistanceGraph(createCustomWidget("All Runs: Mean Hamming Distance", true))
{
	ui.setupUi(this);
	/* create settings object*/
	settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TK", "metavis", this);
	setStyleSheet(styleSheet() + "QMainWindow::separator {background: rgb(200, 200, 200);width: 1px;height: 1px;}");
	setStyleSheet(styleSheet() + "QTabBar::tab:selected {color: rgb(0, 122, 204);}");
	setStyleSheet(styleSheet() + "QTabWidget::pane {border-top: 0px solid #C2C7CB;margin: -9px -9px -13px -9px;}");

	readMainWindowSettings();
	createBitField();
	createProjectManager();
	createTSNE();
} 




void metavis::openSetting() {
	SettingDialog settingDialog(settings, this);
	/* Blocking operation */
	settingDialog.exec();
}

metavis::~metavis()
{
	writeActualMainWindowSettings();
}


GraphView* metavis::createCustomWidget(QString titleString, bool tabToLast)
{
	DockableGraphView* dock = new DockableGraphView(this, titleString);
	qDebug() << titleString;
	if (tabToLast && lastDocked) {
		tabifyDockWidget(lastDocked, dock);
	}
	else {
		addDockWidget(Qt::LeftDockWidgetArea, dock);
		lastDocked = dock;
	}
	return dock->view;
}

void metavis::createBitField()
{
	bitField = new GraphView(this, Bound(-0.1, 1.1, 0.0, 1601.0));
	bitField->setUseFixedBound(true);
	bitField->setMinimumSize(200, 200);
	bitField->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	bitField->maxIter = -2;
	bitField->useInterval = true;
	//this->setCentralWidget(bitField);
	QVBoxLayout* layout = new QVBoxLayout;
	layout->addWidget(bitField);
	RangeSlider* rangeSlider = new RangeSlider(this);
	rangeSlider->setMinimumSize(100, 50);
	rangeSlider->setMinRange(-2);
	rangeSlider->setMaxRange(100);
	connect(rangeSlider, &RangeSlider::maxChanged,
		bitField, &GraphView::setMaxIter);
	connect(rangeSlider, &RangeSlider::minChanged,
		bitField, &GraphView::setMinIter);
	rangeSlider->setMinSliderValue(-2);
	rangeSlider->setMaxSliderValue(100);
	layout->addWidget(rangeSlider);
	ui.BitFieldWidget->setLayout(layout);
}

void metavis::createProjectManager()
{
	QDockWidget* dockWidget = new QDockWidget(this);
	ProjectManager* manager = new ProjectManager(this, this);
	dockWidget->setWindowTitle("Project Manager");
	dockWidget->setWidget(manager);
	addDockWidget(Qt::RightDockWidgetArea, dockWidget);
}

void metavis::createTSNE()
{
	tsneWidget = new tsneIteractive(this);
	ui.tabWidget->addTab(tsneWidget, "tSNE");
}

void metavis::writeActualMainWindowSettings()
{
	settings->beginGroup("MainWindow");
	settings->setValue("maximized", isMaximized());
	if (!isMaximized()) {
		/* position and size of the window if not maximized */
		settings->setValue("pos", pos());
		settings->setValue("size", size());
		settings->setValue("screenCount", QApplication::desktop()->screenCount());
	}
	settings->endGroup();
}

void metavis::readMainWindowSettings()
{
	settings->beginGroup("MainWindow");
	if (QApplication::desktop()->screenCount() == settings->value("screenCount", 1)) {
		//Only when same screeenCount move the window;
		move(settings->value("pos", QPoint(200, 200)).toPoint());
	}
	resize(settings->value("size", QSize(600, 400)).toSize());
	if (settings->value("maximized", false).toBool()) {
		showMaximized();
	}
	settings->endGroup();
}


QColor metavis::interpolate(QColor& first, QColor& second, double alpha)
{
	double firstH, firstS, firstL;
	double secondH, secondS, secondL;

	first.getHslF(&firstH, &firstS, &firstL);
	second.getHslF(&secondH, &secondS, &secondL);

	const double h = util::linearInterpolate(firstH, secondH, alpha);
	const double s = util::linearInterpolate(firstS, secondS, alpha);
	const double l = util::linearInterpolate(firstL, secondL, alpha);

	return QColor::fromHslF(h,s,l);
}


void metavis::updateBitFieldColors()
{
	QColor best(64, 186, 37);
	QColor worst(255, 19, 71);
	double bestValue = 32;
	double worstValue = 46;
	for (GraphDataPoint& data : runList.back().dotsForBitField) {
		data.color = interpolate(best, worst, std::clamp(util::inverseLinearInterpolation(bestValue, worstValue, data.orginalPoint->objectiveFunction), 0.0, 1.0));
	}
}






void metavis::openFile()
{
	qDebug() << "openFile";
	QStringList pathList = QFileDialog::getOpenFileNames(this, "Open LogFile", QStandardPaths::displayName(QStandardPaths::DesktopLocation), "Metavis Logfile (*.metalog)");
	if (pathList.isEmpty()) {
		qDebug() << "No file selected";
		return;
	}
	//int oldIndex = runVec.size();
	int size = runList.size();
	for (int i = 0; i < pathList.size(); i++) {
		qDebug() << "file:" << pathList[i];
		runList.push_back(RunData(pathList[i].toStdString()));
	}
	for (std::list<RunData>::iterator iter = std::next(runList.begin(), size); iter != runList.end(); iter++) {
		QColor runColor = multiBestGraph->generateNextColorForGraph();
		multiBestGraph->addLine(&iter->bestSolutionPerIteration, &*iter, runColor);
		multiAvgGraph->addLine(&iter->averageSolutionPerItertion, &*iter, runColor);
		multiMaxGraph->addLine(&iter->maxSolutionPerItertion, &*iter, runColor);
		multiMinGraph->addLine(&iter->minSolutionPerItertion, &*iter, runColor);
		multiMeanHammingDistanceGraph->addLine(&iter->meanHammingDistancePerIteration, &*iter, runColor);
	}


	/*
	for (int i = 0; i < runList.size(); i++) {
		QColor runColor = multiBestGraph->generateNextColorForGraph();
		multiBestGraph->addLine(&runList[i].bestSolutionPerIteration, &runList[i], runColor);
		multiAvgGraph->addLine(&runList[i].averageSolutionPerItertion, &runList[i], runColor);
		multiMaxGraph->addLine(&runList[i].maxSolutionPerItertion, &runList[i], runColor);
		multiMinGraph->addLine(&runList[i].minSolutionPerItertion, &runList[i], runColor);
		//multiMeanHammingDistanceGraph->addLine(&runVec[i].meanHammingDistancePerIteration, &runVec[i], runColor);
	}*/
	/*std::vector<RunData>::iterator end = runVec.end();
	for (int i = 0; i < pathList.size(); i++) {
		qDebug() << "file:" << pathList[i];
		runVec.push_back(RunData(pathList[i].toStdString()));
	}
	for (std::vector<RunData>::iterator iter = end; iter != runVec.end(); iter++) {
		QColor runColor = multiBestGraph->generateNextColorForGraph();
		multiBestGraph->addLine(&iter->bestSolutionPerIteration, &*iter, runColor);
		multiAvgGraph->addLine(&iter->averageSolutionPerItertion, &*iter, runColor);
		multiMaxGraph->addLine(&iter->maxSolutionPerItertion, &*iter, runColor);
		multiMinGraph->addLine(&iter->minSolutionPerItertion, &*iter, runColor);
		multiMeanHammingDistanceGraph->addLine(&iter->meanHammingDistancePerIteration, &*iter, runColor);
	}*/
	//actualBestAverageGraph->addLine(runVec[0].bestSolutionPerIteration, QColor(255, 0, 0));
	//actualBestAverageGraph->addLine(runVec[0].averageSolutionPerItertion, QColor(0, 0, 255));
	//actualMinMaxGraph->addLine(runVec[0].minSolutionPerItertion, QColor(255, 0, 0));
	//actualMinMaxGraph->addLine(runVec[0].maxSolutionPerItertion, QColor(0, 0, 255));
	//actualMinMaxGraph->addDots(runVec[0].dotsForDistribution, QColor(255, 165, 0, 100));
	//for (auto iter = runVec[0].particleMap.begin(); iter != runVec[0].particleMap.end(); iter++) {
	//	actualParticleGraph->addLine(iter->second);
	//}
	////Test
	bitField->addDots(&runList.back().dotsForBitField, &runList.back(), QColor(255, 165, 0, 100));
	updateBitFieldColors();
	bitField->graphSeriesVec.back().useDataPointColor = true;
	tsneWidget->assignRunData(&runList.back());
	//actualMeanHmmingDistanceGraph->addLine(runVec[0].meanHammingDistancePerIteration, QColor(255, 0, 0));


}
