/*UVOS*/

/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
 *
 * MAClient is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPL) version 
 * 3 as published by the Free Software Foundation.
 *
 * MAClient is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MAClient.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "editprofiledialog.h"
#include "ui_editprofiledialog.h"
#include <uvosled.h>
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include <opencv2/imgproc.hpp>

#include "configurecameradialog.h"

EditProfileDialog::EditProfileDialog(Cameras* cameras, const Profile profile, QWidget *parent) :
	QDialog(parent),
	profile_(profile),
	cameras_(cameras),
	ui(new Ui::EditProfileDialog)
{
	ui->setupUi(this);
	QString name = profile_.getName();
	if(!name.isEmpty())
		ui->lineEditName->setText(name);
	ui->doubleSpinBoxBrightness->setValue(profile_.lighting.brightness*100.0);
	ui->doubleSpinBoxExposure->setValue(profile_.exposureTime);
	ui->doubleSpinBox_kFactor->setValue(profile_.kFactor);

	qDebug()<<"Mask: "<<profile_.lighting.mask<<" & "<<(profile_.lighting.mask & CHANNEL_A);

	ui->checkBoxCh1->setChecked(profile_.lighting.mask & CHANNEL_A);
	ui->checkBoxCh2->setChecked(profile_.lighting.mask & CHANNEL_B);
	ui->checkBoxCh3->setChecked(profile_.lighting.mask & CHANNEL_C);
	ui->checkBoxCh4->setChecked(profile_.lighting.mask & CHANNEL_D);

	ui->checkBoxNodistort->setChecked(profile_.nodistort);

	std::vector<cam::Camera::Description> descs = cameras_->getCameras();
	profile_.setCamerasSetupsFromDescription(descs);

	if(profile_.cameras.size() > 0)
	{
		uint64_t min, max;
		std::shared_ptr<Camera> cam = cameras_->getCamera(profile_.cameras[0].id);
		if(cam)
		{
			cam->cam()->getExposureTimeLimits(min, max);
			ui->doubleSpinBoxExposure->setMaximum(max/1000000.0);
			ui->doubleSpinBoxExposure->setMinimum(min/1000000.0);
		}
	}

	ui->calLed->setLit(profile_.calcurve.data);
	ui->ledLightmap->setLit(profile_.lightmap.data);

	connect(ui->doubleSpinBoxBrightness, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.lighting.brightness = in/100.0;});
	connect(ui->doubleSpinBoxExposure, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in;});
	connect(ui->doubleSpinBox_kFactor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.kFactor = in;});
	connect(ui->lineEditName, &QLineEdit::textChanged, [this](QString in){profile_.setName(in);});
	connect(ui->checkBoxCh1, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
	connect(ui->checkBoxCh2, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
	connect(ui->checkBoxCh3, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
	connect(ui->checkBoxCh4, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
	connect(ui->pushButton, &QPushButton::clicked, this, &EditProfileDialog::configureCamera);
	connect(ui->checkBoxNodistort, &QCheckBox::stateChanged, [this](int state){profile_.nodistort = state == Qt::Checked; setConfigured();});
	connect(ui->pushButtonCalLoad, &QPushButton::clicked, this, &EditProfileDialog::loadCalcurve);
	connect(ui->pushButtonLightmapLoad, &QPushButton::clicked, this, &EditProfileDialog::loadLightmap);
	connect(ui->pushButtonCalClear,  &QPushButton::clicked, [this](){profile_.calcurve.release(); ui->calLed->setLit(profile_.calcurve.data);});
	connect(ui->pushButtonLightmapClear,  &QPushButton::clicked, [this](){profile_.lightmap.release(); ui->ledLightmap->setLit(profile_.lightmap.data);});
	ui->listView->setCameras(cameras_->getCameras());
	ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
	setConfigured();
}

void EditProfileDialog::loadLightmap()
{
	QString fileName = QFileDialog::getOpenFileName(this, "Open Lightmap", "./", "*.mat");
	if(!fileName.isEmpty())
	{
		profile_.lightmap.release();
		cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ);
		matf["image"]>>profile_.lightmap;
		matf.release();
		if(matf.isOpened() && (!profile_.lightmap.data || profile_.lightmap.type() != CV_32FC1))
		{
			profile_.lightmap.release();
			QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid lightmap");
		}
		else if(!profile_.lightmap.data)
		{
			QMessageBox::warning(this, "Can no open", "Can not open file selected");
		}
		profile_.lightmap = cv::mean(profile_.lightmap)/profile_.lightmap;
		cv::GaussianBlur(profile_.lightmap, profile_.lightmap, cv::Size(51,51), 8);

		ui->ledLightmap->setLit(profile_.lightmap.data);
	}
}

void EditProfileDialog::loadCalcurve()
{
	QString fileName = QFileDialog::getOpenFileName(this, "Open Cal Curve", "./", "*.mat");
	if(!fileName.isEmpty())
	{
		profile_.calcurve.release();
		cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ);
		matf["cal"]>>profile_.calcurve;

		if(matf.isOpened() && (!profile_.calcurve.data || profile_.calcurve.type() != CV_32FC1 || profile_.calcurve.rows != 2))
		{
			profile_.calcurve.release();
			QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid cal curve");
		}
		else if(!profile_.calcurve.data)
		{
			QMessageBox::warning(this, "Can no open", "Can not open file selected");
		}
		matf.release();
		ui->calLed->setLit(profile_.calcurve.data);
	}
}

bool EditProfileDialog::setConfigured()
{
	std::vector<cam::Camera::Description> descs = cameras_->getCameras();
	std::vector<bool> configured(descs.size(), profile_.nodistort);

	for(size_t i = 0; i< profile_.cameras.size(); ++i)
	{
		auto& profileCamera = profile_.cameras[i];
		if(profileCamera.remapMap.xMat.data)
		{
			for(auto& camera : descs)
			{
				if(camera.getId() == profileCamera.id)
					configured[i] = true;
			}
		}
	}
	ui->listView->setConfigured(configured);
	bool fullyConfigured = true;
	for(bool config : configured)
	{
		if(!config)
			fullyConfigured = false;
	}
	return fullyConfigured;
}

void EditProfileDialog::invalidateCameras()
{
	for(size_t i = 0; i< profile_.cameras.size(); ++i)
	{
		profile_.cameras[i].bgmask.release();
		profile_.cameras[i].remapMap.xMat.release();
		profile_.cameras[i].remapMap.yMat.release();
		profile_.cameras[i].darkmap.release();
	}
	setConfigured();
}

void EditProfileDialog::configureCamera()
{
	std::vector<cam::Camera::Description> descs = ui->listView->getSelectedDescriptions();
	qDebug()<<"descs"<<descs.size();
	if(!descs.empty())
	{
		qDebug()<<"want to edit id"<<descs[0].getId();
		size_t i = 0;
		for(; i < profile_.cameras.size(); ++i)
		{
			qDebug()<<"test"<<profile_.cameras[i].id ;
			if(profile_.cameras[i].id == descs[0].getId())
			{
				std::shared_ptr<Camera> camera = cameras_->getCamera(profile_.cameras[i].id);
				if(camera)
				{
					ConfigureCameraDialog diag(profile_.cameras[i], camera, profile_.exposureTime, profile_.nodistort, this);
					diag.show();
					int ret = diag.exec();
					if(ret == QDialog::Accepted)
						profile_.cameras[i] = diag.getCameraSetup();
				}
			}
		}
		setConfigured();
	}
}

void EditProfileDialog::accept()
{
	if(!setConfigured())
		QMessageBox::information(this, "Unfinished", "Can not accept with unconfigured cameras");
	else if(profile_.getName().isEmpty() || profile_.getName() == "Unamed")
		QMessageBox::information(this, "Unfinished", "A profile name is required");
	else
		QDialog::accept();
}

void EditProfileDialog::setMask()
{
	uint8_t mask = (ui->checkBoxCh1->isChecked() ? CHANNEL_A : 0) |
				   (ui->checkBoxCh2->isChecked() ? CHANNEL_B : 0) |
				   (ui->checkBoxCh3->isChecked() ? CHANNEL_C : 0) |
				   (ui->checkBoxCh4->isChecked() ? CHANNEL_D : 0);
	profile_.lighting.mask = mask;
}

EditProfileDialog::~EditProfileDialog()
{
	delete ui;
}
