#include "scatter3d.h"

#include <Q3DScatter>
#include <QBoxLayout>
#include <QScatter3DSeries>
#include <QScatterDataArray>
#include <QScatterDataProxy>


Scatter3D::Scatter3D(QWidget * parent): QWidget{parent} {
	curGraphic = 0;
#if QT_VERSION_MAJOR == 5
	canvas     = new QtDataVisualization::Q3DScatter();
#else
	canvas     = new Q3DScatter();
#endif
	canvas->setFlag(Qt::FramelessWindowHint);
	canvas->axisZ()->setReversed(true);
#if QT_VERSION_MAJOR == 5
	canvas->setShadowQuality(QtDataVisualization::QAbstract3DGraph::ShadowQualityNone);
#else
	canvas->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
#endif
	container = QWidget::createWindowContainer(canvas);
	setLayout(new QVBoxLayout(this));
	layout()->setContentsMargins(0, 0, 0, 0);
	layout()->addWidget(container);
}


Scatter3D::~Scatter3D() {
	clear();
	canvas->setParent(nullptr);
	canvas->deleteLater();
}


QColor Scatter3D::graphicColor(int index) const {
	return graphics[index].series->baseColor();
}


float Scatter3D::graphicPointSize(int index) const {
	return graphics[index].series->itemSize();
}


Scatter3D::Mesh Scatter3D::graphicMesh(int index) const {
	return graphics[index].series->mesh();
}


bool Scatter3D::graphicMeshSmooth(int index) const {
	return graphics[index].series->isMeshSmooth();
}


bool Scatter3D::labelAutoRotation() const {
	return canvas->axisX()->labelAutoRotation() == 0;
}


void Scatter3D::setCurrentGraphic(int arg) {
	if (arg < 0 || arg >= graphics.size()) return;
	curGraphic = arg;
}


void Scatter3D::setGraphicsCount(int count) {
	if (count < 0) return;
	while (graphics.size() < count) {
		addGraphic();
	}
	while (graphics.size() > count) {
		auto sg = graphics.takeLast();
		canvas->removeSeries(sg.series);
		delete sg.series;
	}
	container->update();
}


void Scatter3D::setGraphicColor(const QColor & color, int index) {
	graphics[index].series->setBaseColor(color);
	container->update();
}


void Scatter3D::setGraphicPointSize(float sz, int index) {
	graphics[index].series->setItemSize(sz);
	container->update();
}


void Scatter3D::setGraphicMesh(Mesh mesh, int index) {
	graphics[index].series->setMesh(mesh);
	container->update();
}


void Scatter3D::setGraphicMeshSmooth(bool smooth, int index) {
	graphics[index].series->setMeshSmooth(smooth);
	container->update();
}


void Scatter3D::addGraphic(const QColor & color, float pointSize, Mesh mesh, bool meshSmooth) {
	Scatter3DGraphic sg;
#if QT_VERSION_MAJOR == 5
	sg.data   = new QtDataVisualization::QScatterDataProxy();
	sg.series = new QtDataVisualization::QScatter3DSeries(sg.data);
#else
	sg.data   = new QScatterDataProxy();
	sg.series = new QScatter3DSeries(sg.data);
#endif
	sg.series->setItemSize(pointSize);
	sg.series->setBaseColor(color);
	sg.series->setMesh(mesh);
	sg.series->setMeshSmooth(meshSmooth);
	graphics.append(sg);
	canvas->addSeries(sg.series);
	container->update();
}


void Scatter3D::removeGraphic(int index) {
	if (index < 0 || index >= graphics.size()) return;
	canvas->removeSeries(graphics[index].series);
	delete graphics[index].series;
	graphics.remove(index);
}


void Scatter3D::clear() {
	for (auto g: graphics)
		g.data->resetArray(nullptr);
}


void Scatter3D::setLabelAutoRotation(bool on) {
	if (on) {
		canvas->axisX()->setLabelAutoRotation(90);
		canvas->axisY()->setLabelAutoRotation(90);
		canvas->axisZ()->setLabelAutoRotation(90);
	} else {
		canvas->axisX()->setLabelAutoRotation(0);
		canvas->axisY()->setLabelAutoRotation(0);
		canvas->axisZ()->setLabelAutoRotation(0);
	}
	container->update();
}


void Scatter3D::setGraphicData(const QVector<QVector3D> & points, int index) {
	auto arr = new DataArray();
	arr->reserve(points.size());
	for (const auto & p: points) {
		arr->append(p);
	}
	graphics[index].data->resetArray(arr);
	container->update();
}


void Scatter3D::setGraphicData(DataArray * newArray, int index) {
	graphics[index].data->resetArray(newArray);
	container->update();
}


void Scatter3D::addPoint(const QVector3D & point, int index) {
	graphics[index].data->addItem(point);
}
