#include "stdafx.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "volumerenderwindow.h"

/*!
Private data for MainWindow
*/
struct MainWindowPrivate
{
	VolumeRenderer* renderer;
	GLWindow* renderWindow;
	VolumeMetaData currentVolume;
	Ui::MainWindowClass ui;

public:
	MainWindowPrivate() :
		renderer(nullptr)
	{}
};

MainWindow::MainWindow(QWidget *parent)
	: QMainWindow(parent), d(*new MainWindowPrivate)
{
	d.renderer = new VolumeRenderer;

	d.ui.setupUi(this);

	d.ui.volumeInfoContainer->setVisible(false);

	setupRendering();
}

MainWindow::~MainWindow()
{
	delete &d;
}

void MainWindow::setupRendering()
{
	qDebug()<<"Setting up renderer window";

	//the window gets the container as owner later, so we dont need to worry about deletion
	//the window takes ownership of the renderer
	d.renderWindow = new VolumeRenderWindow(d.renderer);

	//for errors
	connect(d.renderWindow,SIGNAL(initializeFailed(const QString&)),SLOT(initializeError(const QString&)));

	//layout must be created here, because ui designer is stoopid
	QLayout* layout = new QGridLayout(d.ui.renderWidget);
	layout->setMargin(0);

	QWidget* container = d.renderWindow->createWindowContainer(d.ui.renderWidget);
	layout->addWidget(container);
	container->setVisible(true);

	//connect stuff that cannot be done in designer
	connect(d.ui.animateCheckbox,SIGNAL(toggled(bool)),d.renderWindow,SLOT(setAnimating(bool)));
	connect(d.renderer,SIGNAL(distanceChanged(float)),SLOT(rendererDistanceChanged(float)));

	connect(d.ui.fixMatrixCheckbox,SIGNAL(toggled(bool)),d.renderer,SLOT(setFixSlicingMatrix(bool)));

	connect(d.ui.bbCheckbox,SIGNAL(toggled(bool)),d.renderer,SLOT(setRenderBoundingBox(bool)));

	startTimer(1000,Qt::TimerType::VeryCoarseTimer);
}

void MainWindow::initializeError(const QString& err)
{
	QMessageBox::critical(this,tr("Error during setup"),tr("Error during OpenGL setup:\n%1").arg(err));

	//nothing we can do...
	qApp->exit(1);
}

void MainWindow::sliderUpdateSilent(QSlider* s, const int val)
{
	bool b = s->blockSignals(true);
	s->setValue(val);
	s->blockSignals(b);
}

void MainWindow::timerEvent(QTimerEvent* te)
{
	d.ui.fpsLabel->setText(tr("FPS: %1 (%2/%3 slices)").arg(
		QString::number(d.renderer->getFPS()), 
		QString::number(d.renderer->getLastRenderedSliceCount()), 
		QString::number(d.renderer->getLastSliceCount()))
		);
}

void MainWindow::rendererDistanceChanged(float dist)
{
	d.ui.zoomSlider->setValue( qRound(dist*10.0f) );
}

void MainWindow::on_zoomSlider_valueChanged(int val)
{
	d.renderer->setDistance(val / 10.0f);
}

void MainWindow::on_orthoCheckbox_toggled(bool val)
{
	d.renderer->setProjectionType(val ? VolumeRenderer::ProjectionType::Orthographic : VolumeRenderer::ProjectionType::Perspective);
}


void MainWindow::on_lightDirectionCheckbox_toggled(bool val)
{
	d.renderer->setShowLightDirection(val);
}

void MainWindow::on_smoothCheckBox_toggled(bool v)
{
	d.renderer->setSmoothVolume(v);
}

void MainWindow::on_sigmaSlider_valueChanged(int val)
{
	d.ui.sigmaSpinBox->setValue(val / 100.0f);
}

void MainWindow::on_sigmaSpinBox_valueChanged(double val)
{
	d.renderer->setGaussianSigma(val);

	int iVal = val * 100.0f;
	sliderUpdateSilent(d.ui.sigmaSlider,iVal);
}

void MainWindow::on_sliceSlider_valueChanged(int val)
{
	d.ui.sliceSpinBox->setValue(1.0f / val);
}

void MainWindow::on_sliceSpinBox_valueChanged(double val)
{
	d.renderer->setSliceDelta(val);
	
	int iVal = qRound(1/val);
	sliderUpdateSilent(d.ui.sliceSlider,iVal);
}

void MainWindow::on_windowMinSlider_valueChanged(int val)
{
	d.ui.windowMinSpinBox->setValue(val / 1000.0f);
}

void MainWindow::on_windowMinSpinBox_valueChanged(double val)
{
	d.renderer->setLowerWindowLimit(val);

	//convert float to range [0,1000]
	int iVal = val * 1000;
	d.ui.windowMaxSlider->setMinimum(iVal);
	d.ui.windowMaxSpinBox->setMinimum(val);

	sliderUpdateSilent(d.ui.windowMinSlider,iVal);
}


void MainWindow::on_windowMaxSlider_valueChanged(int val)
{
	d.ui.windowMaxSpinBox->setValue(val / 1000.0f);
}

void MainWindow::on_windowMaxSpinBox_valueChanged(double val)
{
	d.renderer->setUpperWindowLimit(val);

	//convert float to range [0,1000]
	int iVal = val * 1000;
	d.ui.windowMinSlider->setMaximum(iVal);
	d.ui.windowMinSpinBox->setMaximum(val);

	sliderUpdateSilent(d.ui.windowMaxSlider,iVal);
}

void MainWindow::on_dofCheckBox_toggled(bool v)
{
	d.ui.dofGroupBox->setVisible(v);
	d.renderer->setApplyDOF(v);
}

void MainWindow::on_focalPlaneSlider_valueChanged(int val)
{
	d.renderer->setFocalPlane(val / 1000.0f);
}

void MainWindow::on_blurAmountSlider_valueChanged(int val)
{
	d.ui.blurAmountSpinBox->setValue(val / 1000.0f);
}

void MainWindow::on_blurAmountSpinBox_valueChanged(double val)
{
	d.renderer->setBlurAmount(val);

	sliderUpdateSilent(d.ui.blurAmountSlider,val * 1000);
}


void MainWindow::on_loadVolumeButton_clicked()
{
	QDir d1("volumes");
	QDir d2("../volumes");

	QString file = QFileDialog::getOpenFileName(this,tr("Select volume to open"),
		d1.exists() ? d1.path() : d2.path(),
		tr("VoxelBlur volume metadata (*.vbvolume)"));
	if(file.isNull())
	{
		qDebug()<<"User canceled file loading";
	}
	else
	{
		qDebug()<<"User selected file "<<QFileInfo(file).absoluteFilePath();
		VolumeMetaData volData;
		bool ok = d.renderer->loadVolume(file,&volData);
		if(ok)
		{
			qDebug()<<"Volume successfully loaded";
			d.currentVolume = d.renderer->getCurrentVolume();

			//update volume info display
			updateVolumeInfo();			
		}
		else
		{
			qWarning()<<"Volume could not be loaded";
			QMessageBox::critical(this,tr("Error loading volume"),
				tr("There was an error loading the volume %1. Check the log for more information.").arg(file),QMessageBox::Ok);
		}
	}
}

void MainWindow::updateVolumeInfo()
{
	d.ui.volumeNameLabel->setText(d.currentVolume.name);
	d.ui.volumeDimensionLabel->setText(QString("%1x%2x%3").arg(d.currentVolume.width).arg(d.currentVolume.height).arg(d.currentVolume.depth));
	d.ui.volumeScalingLabel->setText(QString("%1x%2x%3").arg(d.currentVolume.aspectX).arg(d.currentVolume.aspectY).arg(d.currentVolume.aspectZ));

	static QString ucharText = tr("8-bit unsigned integer");
	static QString ushortText = tr("16-bit unsigned integer");
	d.ui.volumeDataTypeLabel->setText(tr("%1 (%2 bits used)").arg(d.currentVolume.type == VolumeMetaData::VolumeDataType::ushort ? ushortText : ucharText,QString::number(d.currentVolume.actualBits)));

	QString source = d.currentVolume.source;
	QUrl u (source,QUrl::StrictMode);
	if(u.isValid())
	{
		//valid url, create hyperlink
		static QString pattern("<a href=\"%1\">%2</a>");
		d.ui.volumeSourceLabel->setText(pattern.arg(u.toEncoded(),u.url()));
		d.ui.volumeSourceLabel->setTextFormat(Qt::TextFormat::RichText);
	}
	else
	{
		//normal text
		d.ui.volumeSourceLabel->setText(source);
		d.ui.volumeSourceLabel->setTextFormat(Qt::TextFormat::PlainText);
	}

	d.ui.noVolumeLabel->setVisible(false);
	d.ui.volumeInfoContainer->setVisible(true);
}