/*
    QGL PrimitiveEditor
    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 "primitiveeditor.h"

#include "glmesh.h"
#include "glprimitives.h"
#include "ui_primitiveeditor.h"

#include <QMetaEnum>
#include <qad_types.h>


PrimitiveEditor::PrimitiveEditor(QWidget * parent): QWidget(parent), ui(new Ui::PrimitiveEditor) {
	view        = 0;
	can_replace = false;
	ui->setupUi(this);
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
	ui->spinSegments->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
	ui->spinSegments2->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
#endif
	editors[Plane] << ui->widgetWidth;
	editors[Plane] << ui->widgetLength;
	editors[Plane] << ui->widgetSegmentsW;
	editors[Plane] << ui->widgetSegmentsL;
	editors[Cube] << ui->widgetWidth;
	editors[Cube] << ui->widgetLength;
	editors[Cube] << ui->widgetHeight;
	editors[Cube] << ui->widgetSegmentsW;
	editors[Cube] << ui->widgetSegmentsL;
	editors[Cube] << ui->widgetSegmentsH;
	editors[Ellipsoid] << ui->widgetRadius1;
	editors[Ellipsoid] << ui->widgetSegments;
	editors[Ellipsoid] << ui->widgetSegments2;
	editors[Ellipsoid] << ui->widgetAngle;
	editors[Disc] << ui->widgetRadius1;
	editors[Disc] << ui->widgetSegments;
	editors[Disc] << ui->widgetAngle;
	editors[Cone] << ui->widgetRadius1;
	editors[Cone] << ui->widgetHeight;
	editors[Cone] << ui->widgetSegments;
	editors[Cylinder] << ui->widgetRadius1;
	editors[Cylinder] << ui->widgetHeight;
	editors[Cylinder] << ui->widgetSegments;
	editors[Cylinder] << ui->widgetAngle;
	editors[Torus] << ui->widgetRadius1;
	editors[Torus] << ui->widgetRadius2;
	editors[Torus] << ui->widgetSegments;
	editors[Torus] << ui->widgetSegments2;
	editors[Torus] << ui->widgetAngle;
	QSet<QWidget *> all;
	QMetaEnum me = metaObject()->enumerator(0);
	for (int i = 0; i < me.keyCount(); ++i) {
		ui->comboPrimitives->addItem(me.key(i));
		all.unite(QList2QSet(editors[(PrimitiveType)me.value(i)]));
	}
	all_editors = all.values();
	foreach(QWidget * w, all_editors) {
		if (w->layout()) w->layout()->setContentsMargins(0, layout()->spacing(), 0, 0);
	}

	ui->comboPrimitives->setCurrentIndex(Plane);
	on_comboPrimitives_currentIndexChanged(ui->comboPrimitives->currentIndex());
}


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


void PrimitiveEditor::assignQGLView(QGLView * v) {
	view = v;
	connect(view, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
	selectionChanged();
}


ObjectBase * PrimitiveEditor::createCurrent() {
	if (!view) return nullptr;
	QVariantList params;
	Mesh * m = createMesh(params);
	if (!m) return nullptr;
	ObjectBase * o = new ObjectBase(m);
	o->setColor(ui->colorButton->color());
	o->setName(ui->comboPrimitives->currentText());
	o->setProperty("primitive", params);
	view->scene()->addObject(o);
	view->scene()->selectObject(o);
	delete m;
	return o;
}


Mesh * PrimitiveEditor::createMesh(QVariantList & params) {
	Mesh * m         = 0;
	PrimitiveType pt = (PrimitiveType)ui->comboPrimitives->currentIndex();
	params << pt;
	switch (pt) {
	case Plane:
		m = Primitive::plane(ui->spinWidth->value(), ui->spinLength->value(), ui->spinSegmentsW->value(), ui->spinSegmentsL->value());
		params << ui->spinWidth->value() << ui->spinLength->value() << ui->spinSegmentsW->value() << ui->spinSegmentsL->value();
		break;
	case Cube:
		m = Primitive::cube(ui->spinWidth->value(),
							ui->spinLength->value(),
							ui->spinHeight->value(),
							ui->spinSegmentsW->value(),
							ui->spinSegmentsL->value(),
							ui->spinSegmentsH->value());
		params << ui->spinWidth->value() << ui->spinLength->value() << ui->spinHeight->value() << ui->spinSegmentsW->value()
			   << ui->spinSegmentsL->value() << ui->spinSegmentsH->value();
		break;
	case Ellipsoid:
		m = Primitive::ellipsoid(ui->spinSegments->value(), ui->spinSegments2->value(), ui->spinRadius->value(), ui->spinAngle->value());
		params << ui->spinSegments->value() << ui->spinSegments2->value() << ui->spinRadius->value() << ui->spinAngle->value();
		break;
	case Disc:
		m = Primitive::disc(ui->spinSegments->value(), ui->spinRadius->value(), ui->spinAngle->value());
		params << ui->spinSegments->value() << ui->spinRadius->value() << ui->spinAngle->value();
		break;
	case Cone:
		m = Primitive::cone(ui->spinSegments->value(), ui->spinRadius->value(), ui->spinHeight->value());
		params << ui->spinSegments->value() << ui->spinRadius->value() << ui->spinHeight->value();
		break;
	case Cylinder:
		m = Primitive::cylinder(ui->spinSegments->value(), ui->spinRadius->value(), ui->spinHeight->value(), ui->spinAngle->value());
		params << ui->spinSegments->value() << ui->spinRadius->value() << ui->spinHeight->value() << ui->spinAngle->value();
		break;
	case Torus:
		m = Primitive::torus(ui->spinSegments->value(),
		                     ui->spinSegments2->value(),
		                     ui->spinRadius->value(),
		                     ui->spinRadius2->value(),
		                     ui->spinAngle->value());
		params << ui->spinSegments->value() << ui->spinSegments2->value() << ui->spinRadius->value() << ui->spinRadius2->value()
			   << ui->spinAngle->value();
		break;
	default: return 0;
	}
	params << ui->flipNormals->isChecked();
	params << ui->colorButton->color();
	if (ui->flipNormals->isChecked()) m->flipNormals();
	return m;
}


void PrimitiveEditor::showEditors() {
	foreach(QWidget * w, all_editors)
		w->hide();
	PrimitiveType pt     = (PrimitiveType)ui->comboPrimitives->currentIndex();
	QList<QWidget *> wds = editors[pt];
	foreach(QWidget * w, wds)
		w->show();
}


void PrimitiveEditor::selectionChanged() {
	ObjectBase * so = view->selectedObject();
	can_replace     = false;
	if (so) {
		QVariantList vl = so->property("primitive", &can_replace).toList();
		if (can_replace && !vl.isEmpty()) {
			PrimitiveType pt = (PrimitiveType)vl.takeFirst().toInt();
			ui->comboPrimitives->setCurrentIndex(pt);
			switch (pt) {
			case Plane:
				ui->spinWidth->setValue(vl.takeFirst().toDouble());
				ui->spinLength->setValue(vl.takeFirst().toDouble());
				if (!vl.isEmpty()) ui->spinSegmentsW->setValue(vl.takeFirst().toInt());
				if (!vl.isEmpty()) ui->spinSegmentsL->setValue(vl.takeFirst().toInt());
				break;
			case Cube:
				ui->spinWidth->setValue(vl.takeFirst().toDouble());
				ui->spinLength->setValue(vl.takeFirst().toDouble());
				ui->spinHeight->setValue(vl.takeFirst().toDouble());
				if (!vl.isEmpty()) ui->spinSegmentsW->setValue(vl.takeFirst().toInt());
				if (!vl.isEmpty()) ui->spinSegmentsL->setValue(vl.takeFirst().toInt());
				if (!vl.isEmpty()) ui->spinSegmentsH->setValue(vl.takeFirst().toInt());
				break;
			case Ellipsoid:
				ui->spinSegments->setValue(vl.takeFirst().toDouble());
				ui->spinSegments2->setValue(vl.takeFirst().toDouble());
				ui->spinRadius->setValue(vl.takeFirst().toDouble());
				ui->spinAngle->setValue(vl.takeFirst().toDouble());
				break;
			case Disc:
				ui->spinSegments->setValue(vl.takeFirst().toDouble());
				ui->spinRadius->setValue(vl.takeFirst().toDouble());
				ui->spinAngle->setValue(vl.takeFirst().toDouble());
				break;
			case Cone:
				ui->spinSegments->setValue(vl.takeFirst().toDouble());
				ui->spinRadius->setValue(vl.takeFirst().toDouble());
				ui->spinHeight->setValue(vl.takeFirst().toDouble());
				break;
			case Cylinder:
				ui->spinSegments->setValue(vl.takeFirst().toDouble());
				ui->spinRadius->setValue(vl.takeFirst().toDouble());
				ui->spinHeight->setValue(vl.takeFirst().toDouble());
				ui->spinAngle->setValue(vl.takeFirst().toDouble());
				break;
			case Torus:
				ui->spinSegments->setValue(vl.takeFirst().toDouble());
				ui->spinSegments2->setValue(vl.takeFirst().toDouble());
				ui->spinRadius->setValue(vl.takeFirst().toDouble());
				ui->spinRadius2->setValue(vl.takeFirst().toDouble());
				ui->spinAngle->setValue(vl.takeFirst().toDouble());
				break;
			}
			if (!vl.isEmpty()) ui->flipNormals->setChecked(vl.takeFirst().toBool());
			if (!vl.isEmpty()) ui->colorButton->setColor(vl.takeFirst().value<QColor>());
		}
	}
}


void PrimitiveEditor::replaceMesh() {
	if (!view) return;
	if (!can_replace) return;
	ObjectBase * so = view->selectedObject();
	if (!so) return;
	QVariantList params;
	Mesh * m = createMesh(params);
	if (!m) return;
	so->setMesh(m);
	so->setColor(ui->colorButton->color());
	so->setName(ui->comboPrimitives->currentText());
	so->setProperty("primitive", params);
	delete m;
}


void PrimitiveEditor::on_buttonAdd_clicked() {
	createCurrent();
}


void PrimitiveEditor::on_comboPrimitives_currentIndexChanged(int index) {
	showEditors();
}
