/*
    QGLViewWindow
    Ivan Pelipenko peri4ko@yandex.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "qglview_window.h"

#include "glshaders.h"
#include "gltexture_manager.h"
#include "glwidget.h"
#include "qad_types.h"
#include "renderer.h"

#include <QGraphicsRectItem>
#include <QImageReader>
#include <QMessageBox>
#include <piqt.h>


class Effect1: public FramebufferEffectBase {
public:
	Effect1() {
		params.addChild({
			"radius",
			10,
			{{PIValueTree::Attribute::minimum, 1}, {PIValueTree::Attribute::maximum, 4000}}
		});
	}
	~Effect1() { deleteShader(mys); }
	QString name() const { return "Blur"; }
	void reloadShaders() {
		deleteShader(mys);
		QGLEngineShaders::loadShadersMulti(mys, "test1.glsl");
	}
	void draw() {
		if (!mys) return;
		if (!mys->isLinked()) return;

		int radius  = params["radius"].value().toInt();

		auto planes = getFreePlanes(1);
		bindPreviousOutput(0);
		// bindDeferredBuffer(Renderer::dbrNormalZSolid, 1);
		mys->bind();
		mys->setUniformValue("tex_in", 0);
		mys->setUniformValue("radius", radius);
		mys->setUniformValue("sum_div", (GLfloat)(radius + 1));
		mys->setUniformValue("step", QVector2D(1, 0));
		drawScreen(mys);

		setOutputPlane(planes[0]);
		bindPreviousOutput(0);
		mys->setUniformValue("step", QVector2D(0, 1));
		drawScreen(mys);
	}
	QOpenGLShaderProgram * mys = nullptr;
};


QGLViewWindow::QGLViewWindow(QWidget * parent): QMainWindow(parent), Ui::QGLViewWindow() {
	setupUi(this);
	session.setFile("session_qglview_test.conf");
	session.addEntry(this);

	extensions = "All(" + supportedFormats().join(" ") + " *.qgl)";
	extensions += ";;QGLEngine(*.qgl)";

	// view->view()->camera()->setPos(QVector3D(2, 2, 2));
	// view->view()->camera()->setAim(QVector3D());
	// view->view()->camera()->flyToDistance(2.);
	//	view->setFrameShape(QFrame::NoFrame);
	view->view()->setMouseRotateEnabled(true);
	view->view()->setMouseSelectionEnabled(true);
	view->view()->setSelectionHaloEnabled(true);
	view->view()->setHoverHaloEnabled(true);
	view->view()->setDepthStart(0.1);
	view->view()->setSelectionMode(Scene::smMultiSelection);

	auto * e = new Effect1();
	e->setEnabled(false);
	view->view()->renderer_.addFramebufferEffect(e);

	PIValueTree params;
	auto p = e->parameters();
	p.setName(Q2PIString(e->name()));
	params.addChild(p);
	// widgetParameters->setFullEditMode(true);
	widgetParameters->setGrouping(PIValueTreeEdit::Groups);
	widgetParameters->setValue(params);
	/*
		groupShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsEnabled));
		groupEyeAccomodation->setChecked(view->view()->isFeatureEnabled(QGLView::qglEyeAccomodationEnabled));
		groupBloom->setChecked(view->view()->isFeatureEnabled(QGLView::qglBloomEnabled));
		groupMotionBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglMotionBlurEnabled));
		groupReflections->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsEnabled));
		checkSoftShadows->setChecked(view->view()->isFeatureEnabled(QGLView::qglShadowsSoftEnabled));
		groupSSAO->setChecked(view->view()->isFeatureEnabled(QGLView::qglSSAOEnabled));
		spinAccom->setValue(view->view()->feature(QGLView::qglEyeAccomodationTime).toDouble());
		spinAccomMS->setValue(view->view()->feature(QGLView::qglEyeAccomodationMaxSpeed).toDouble());
		checkReflectionsBlur->setChecked(view->view()->isFeatureEnabled(QGLView::qglReflectionsBlur));
		spinShadowmapSize->setValue(view->view()->feature(QGLView::qglShadowsMapSize).toInt());
		spinMotionBlurFactor->setValue(view->view()->feature(QGLView::qglMotionBlurFactor).toDouble());
		spinMotionBlurSteps->setValue(view->view()->feature(QGLView::qglMotionBlurSteps).toInt());
		spinBloomFactor->setValue(view->view()->feature(QGLView::qglBloomFactor).toDouble());
		spinBloomRadius->setValue(view->view()->feature(QGLView::qglBloomRadius).toInt());
		spinBloomThreshold->setValue(view->view()->feature(QGLView::qglBloomThreshold).toDouble());
		spinSSAORadius->setValue(view->view()->feature(QGLView::qglSSAORadius).toInt());
		groupDOF->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldEnabled));
		checkDOFAutoFocus->setChecked(view->view()->isFeatureEnabled(QGLView::qglDepthOfFieldAutoFocusEnabled));
		spinDOFFocus->setValue(view->view()->feature(QGLView::qglDepthOfFieldFocus).toDouble());
		spinDOFDiaphragm->setValue(view->view()->feature(QGLView::qglDepthOfFieldDiaphragm).toDouble());
		spinDOFSpeed->setValue(view->view()->feature(QGLView::qglDepthOfFieldAutoFocusSpeed).toDouble());
	*/
	view->view()->start(-1);
	startTimer(1000 / 60);

	connect(view->view(), SIGNAL(keyEvent(Qt::Key, Qt::KeyboardModifiers)), this, SLOT(view_keyEvent(Qt::Key, Qt::KeyboardModifiers)));
	connect(view->view(), &QGLView::glEndPaint, this, [this]() { labelTimings->setText(view->view()->renderer_.getTimings()); });
	// connect(matEditor, SIGNAL(changed()), this, SLOT(materialChanged()));
	sceneTree->assignQGLView(view->view());
	matEditor->assignQGLView(view->view());
	objectEditor->assignQGLView(view->view());
	primitiveEditor->assignQGLView(view->view());
	viewEditor->assignQGLView(view->view());
	widgetTextures->assignQGLView(view->view());

	auto * o = primitiveEditor->createCurrent();
	o->calculateBoundingBox();
	view->view()->focusOn(o->boundingBox());

	session.load();


	// loadFile("axis.DAE.qgl");
	// matEditor->setMaterial(const_cast<ObjectBase*>(view->view()->scene()->rootObject()->child(0))->material());
	/*Scene * sc = loadScene("truck.obj");
	//view->view()->scene()->addScene(sc);
	sc->rootObject()->moveY(-8);
	for (int i = 0; i < 7; ++i) {
	    sc->rootObject()->moveY(2);
	    view->view()->scene()->addScene(sc);
	}
	//view->view()->scene()->dump();
	delete sc;*/
}


QGLViewWindow::~QGLViewWindow() {
	session.save();
	// delete ps;
}


void QGLViewWindow::changeEvent(QEvent * e) {
	QMainWindow::changeEvent(e);
	if (e->type() == QEvent::LanguageChange) {
		retranslateUi(this);
		return;
	}
}


void QGLViewWindow::timerEvent(QTimerEvent *) {
	// static double t = 0.;
	//((RendererSimple*)(view->view()->renderer()))->mpos = view->view()->mapFromGlobal(QCursor::pos());
	statusBar()->showMessage(QString("FPS: %1").arg(QString::number(view->view()->currentFPS(), 'f', 2)));
}


void QGLViewWindow::loadFile(const QString & path, bool import) {
	prev_path = path;
	QApplication::setOverrideCursor(Qt::WaitCursor);
	QFileInfo fi(path);
	Scene * s = nullptr;
	if (fi.suffix().toLower() == "qgl")
		s = loadFromQGLFile(path);
	else
		s = loadScene(path);
	QApplication::restoreOverrideCursor();
	if (!s) {
		QMessageBox::critical(this, "Import", "Can`t load " + path + "!");
		return;
	}
	s->setName(fi.baseName());
	if (import)
		view->scene()->addScene(s);
	else {
		TextureManager::clearSearchPathes();
		view->scene()->assignFrom(s);
		view->view()->focusOn(view->scene()->boundingBox());
	}
	TextureManager::addSearchPath(fi.absoluteDir().path());
	widgetTextures->showPathes();
	delete s;
}


void QGLViewWindow::on_actionReset_triggered() {
	/// view->view()->removeObject(axis, false);
	view->view()->scene()->clear();
	/// view->view()->addObject(axis);
}


void QGLViewWindow::on_actionImport_triggered() {
	QStringList fl = QFileDialog::getOpenFileNames(this, "Select files", prev_path, extensions);
	if (fl.isEmpty()) return;
	prev_path = fl.back();
	foreach(QString f, fl)
		loadFile(f, true);
}


void QGLViewWindow::on_actionSave_triggered() {
	QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
	if (f.isEmpty()) return;
	if (f.right(4).toLower() != ".qgl") f += ".qgl";
	prev_path = f;
	QApplication::setOverrideCursor(Qt::WaitCursor);
	saveToQGLFile(f, view->scene());
	QApplication::restoreOverrideCursor();
}


void QGLViewWindow::on_actionSaveSelected_triggered() {
	ObjectBase * sel_obj = view->view()->selectedObject();
	if (!sel_obj) return;
	QString f = QFileDialog::getSaveFileName(this, "Select file", prev_path, "QGLView(*.qgl)");
	if (f.isEmpty()) return;
	if (f.right(4).toLower() != ".qgl") f += ".qgl";
	prev_path = f;
	QApplication::setOverrideCursor(Qt::WaitCursor);
	// saveToQGLFile(f, sel_obj);
	QApplication::restoreOverrideCursor();
}


void QGLViewWindow::on_actionOpen_triggered() {
	QString f = QFileDialog::getOpenFileName(this, "Select file", prev_path, extensions);
	if (f.isEmpty()) return;
	prev_path = f;
	loadFile(f);
}


void QGLViewWindow::view_keyEvent(Qt::Key k, Qt::KeyboardModifiers m) {
	// qDebug() << k;
	double spd = 0.2;
	if (m.testFlag(Qt::ShiftModifier)) spd = 0.5;
	switch (k) {
	case Qt::Key_W: view->view()->camera()->moveForward(spd); break;
	case Qt::Key_S: view->view()->camera()->moveBackward(spd); break;
	case Qt::Key_A: view->view()->camera()->moveLeft(spd); break;
	case Qt::Key_D: view->view()->camera()->moveRight(spd); break;
	default: break;
	}
}


void QGLViewWindow::on_buttonParamsApply_clicked() {
	auto fbel   = view->view()->renderer_.framebufferEffects();
	auto params = widgetParameters->value();
	for (auto * e: fbel)
		e->setParameters(params.child(Q2PIString(e->name())));
}


void QGLViewWindow::on_actionArrow_triggered(bool on) {
	actionArrow->setChecked(true);
	actionMove->setChecked(false);
	actionRotate->setChecked(false);
	actionScale->setChecked(false);
	view->view()->setCurrentAction(RendererService::haNoAction);
}


void QGLViewWindow::on_actionMove_triggered(bool on) {
	actionArrow->setChecked(false);
	actionMove->setChecked(true);
	actionRotate->setChecked(false);
	actionScale->setChecked(false);
	view->view()->setCurrentAction(RendererService::haMove);
}


void QGLViewWindow::on_actionRotate_triggered(bool on) {
	actionArrow->setChecked(false);
	actionMove->setChecked(false);
	actionRotate->setChecked(true);
	actionScale->setChecked(false);
	view->view()->setCurrentAction(RendererService::haRotate);
}


void QGLViewWindow::on_actionScale_triggered(bool on) {
	actionArrow->setChecked(false);
	actionMove->setChecked(false);
	actionRotate->setChecked(false);
	actionScale->setChecked(true);
	view->view()->setCurrentAction(RendererService::haScale);
}


#include "glcubemap.h"
void QGLViewWindow::on_pushButton_3_clicked() {
	QString f = QFileDialog::getOpenFileName(this, "Select file", "", "*");
	if (f.isEmpty()) return;
}
