/*
	Copyright 2006-2026 The QElectroTech Team
	This file is part of QElectroTech.

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

	QElectroTech 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 QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementstreeview.h"

#include "../factory/elementfactory.h"
#include "../qetgraphicsitem/element.h"
#include "../qeticons.h"
#include "elementcollectionitem.h"
#include "elementslocation.h"
#include "../qetproject.h"
#include "../diagram.h"
#include "xmlelementcollection.h"
#include "../NameList/nameslist.h"
#include <QPainter>
#include <QScopedPointer>
#include <QDrag>
#include <QStandardItemModel>

static int MAX_DND_PIXMAP_WIDTH = 500;
static int MAX_DND_PIXMAP_HEIGHT = 375;

/**
	@brief ElementsTreeView::ElementsTreeView
	@param parent
*/
ElementsTreeView::ElementsTreeView(QWidget *parent) :
	QTreeView(parent)
{
	// force du noir sur une alternance de blanc (comme le schema) et de gris
	// clair, avec du blanc sur bleu pas trop fonce pour la selection
	//
	// Element icons are rendered with colors read directly from each .elmt
	// file (almost always black linework, matching printed-schematic
	// convention) onto a transparent background -- so this view must keep
	// a light background regardless of the OS/desktop theme, or the icons
	// become invisible on dark themes. QAbstractItemView paints its rows
	// using the viewport's palette, not the view's own, so the palette
	// must be applied to both to actually take effect under every style.
	QPalette qp = palette();
	qp.setColor(QPalette::Text,            Qt::black);
	qp.setColor(QPalette::Base,            Qt::white);
	qp.setColor(QPalette::AlternateBase,   QColor("#e8e8e8"));
	qp.setColor(QPalette::Highlight,       QColor("#678db2"));
	qp.setColor(QPalette::HighlightedText, Qt::black);
	setPalette(qp);
	viewport()->setPalette(qp);
}

/**
	@brief ElementsTreeView::startDrag
	Reimplemented from QTreeView
	@param supportedActions
*/
void ElementsTreeView::startDrag(Qt::DropActions supportedActions)
{
	QModelIndex index = currentIndex();

	if (!index.isValid()) {
		QTreeView::startDrag(supportedActions);
		return;
	}

	if (QStandardItemModel *qsim = static_cast<QStandardItemModel *>(model())) {
		if (ElementCollectionItem *eci = static_cast<ElementCollectionItem *>(qsim->itemFromIndex(index))) {
			ElementsLocation loc (eci->collectionPath());
			if (loc.exist()) {
				startElementDrag(loc);
				return;
			}
		}
	}
	QTreeView::startDrag(supportedActions);
}

/**
	@brief ElementsTreeView::startElementDrag
	Build a QDrag according to the content of location
	@param location : location to use for create the content of the QDrag
*/
void ElementsTreeView::startElementDrag(const ElementsLocation &location)
{
	if (! location.exist()) return;

#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
	QDrag* drag = new QDrag(this);
#else
	QScopedPointer<QDrag> drag(new QDrag(this));
#endif

	QString location_str = location.toString();
	QMimeData *mime_data = new QMimeData();
	mime_data->setText(location_str);

	if (location.isDirectory())
	{
		mime_data->setData("application/x-qet-category-uri",
						   location_str.toLatin1());
		drag->setPixmap(QET::Icons::Folder.pixmap(22, 22));
	}
	else if (location.fileName().endsWith(".qetmak"))
	{
		mime_data->setData("application/x-qet-element-uri", location_str.toLatin1());

		QPixmap macro_pixmap;

		// --- MINI-RENDERER FÜR DAS MAKRO-VORSCHAUBILD ---
		QFile file(location.fileSystemPath());
		if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
			QDomDocument macro_doc;
			if (macro_doc.setContent(&file)) {
				QDomElement root = macro_doc.documentElement();
				if (root.tagName() == "qet_macro") {

					// 1. Unsichtbares Dummy-Projekt erstellen
					QScopedPointer<QETProject> dummy_project(new QETProject());

					// 2. Bauteile in das Dummy-Projekt laden (wie beim echten Drop)
					QDomElement collection_node = root.firstChildElement("collection");
					if (!collection_node.isNull()) {
						QDomNodeList elements = collection_node.elementsByTagName("element");
						for (int i = 0; i < elements.count(); ++i) {
							QDomElement elmt_node = elements.at(i).toElement();
							QString path = elmt_node.attribute("path");
							QDomElement definition = elmt_node.firstChildElement("definition");
							if (!path.isEmpty() && !definition.isNull()) {
								int last_slash = path.lastIndexOf('/');
								QString dir_path = (last_slash != -1) ? path.left(last_slash) : "";
								QString file_name = (last_slash != -1) ? path.mid(last_slash + 1) : path;

								if (!dir_path.isEmpty()) {
									#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
									QStringList parts = dir_path.split('/', QString::SkipEmptyParts);
									#else
									QStringList parts = dir_path.split('/', Qt::SkipEmptyParts);
									#endif
									QString current_path = "";
									for (const QString &part : parts) {
										QString parent_path = current_path;
										if (!current_path.isEmpty()) current_path += "/";
										current_path += part;
										if (current_path == "import") continue;
										NamesList empty_names;
										dummy_project->embeddedElementCollection()->createDir(parent_path, part, empty_names);
									}
								}
								dummy_project->embeddedElementCollection()->addElementDefinition(dir_path, file_name, definition);
							}
						}
					}

					Diagram *dummy_diagram = dummy_project->addNewDiagram();

					// 4. Makro auf dem unsichtbaren Blatt zeichnen
					QDomElement diagram_content_node = root.firstChildElement("diagram_content");
					QDomElement diagram_node = diagram_content_node.firstChildElement("diagram");
					if (!diagram_node.isNull()) {
						QDomNodeList instances = diagram_node.elementsByTagName("element");
						for (int i = 0; i < instances.count(); ++i) {
							QDomElement inst = instances.at(i).toElement();
							QString type = inst.attribute("type");
							if (type.startsWith("macro://")) {
								inst.setAttribute("type", type.replace("macro://", "embed://"));
							}
						}

						dummy_diagram->fromXml(diagram_node, QPointF(0, 0), false, nullptr);
						dummy_diagram->clearSelection();

						// 5. "Screenshot" (Pixmap) von den gezeichneten Elementen machen
						QRectF scene_rect = dummy_diagram->itemsBoundingRect();
						if (!scene_rect.isEmpty()) {
							scene_rect.adjust(-5, -5, 5, 5); // Kleiner Rand
							macro_pixmap = QPixmap(scene_rect.size().toSize());
							macro_pixmap.fill(Qt::transparent); // Transparenter Hintergrund

							QPainter painter(&macro_pixmap);
							painter.setRenderHint(QPainter::Antialiasing);
							dummy_diagram->render(&painter, macro_pixmap.rect(), scene_rect);
						}
					}
				}
			}
		}

		if (macro_pixmap.isNull()) {
			macro_pixmap = QET::Icons::Project.pixmap(32, 32);
		}

		// Bild verkleinern, falls das Makro gigantisch groß ist
		if (macro_pixmap.width() > MAX_DND_PIXMAP_WIDTH || macro_pixmap.height() > MAX_DND_PIXMAP_HEIGHT) {
			macro_pixmap = macro_pixmap.scaled(MAX_DND_PIXMAP_WIDTH, MAX_DND_PIXMAP_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation);
		}

		drag->setPixmap(macro_pixmap);
		// Bild zentriert an die Maus hängen
		drag->setHotSpot(QPoint(macro_pixmap.width() / 2, macro_pixmap.height() / 2));
	}
	else if (location.isElement())
	{
		mime_data->setData("application/x-qet-element-uri",
				   location_str.toLatin1());

			//Build the element for set the pixmap of the QDrag
		int elmt_creation_state;
		QScopedPointer<Element> temp_elmt(
		    ElementFactory::Instance()->createElement(
			location,
			nullptr,
			&elmt_creation_state));
		if (elmt_creation_state) { return; }

		QPixmap elmt_pixmap(temp_elmt->pixmap());
		QPoint elmt_hotspot(temp_elmt->hotspot());

			//Adjust the size of the pixmap if he is too big
		QPoint elmt_pixmap_size(elmt_pixmap.width(),
					elmt_pixmap.height());
		if (elmt_pixmap.width()
				> MAX_DND_PIXMAP_WIDTH
				|| elmt_pixmap.height()
				> MAX_DND_PIXMAP_HEIGHT)
		{
			elmt_pixmap = elmt_pixmap.scaled(
						MAX_DND_PIXMAP_WIDTH,
						MAX_DND_PIXMAP_HEIGHT,
						Qt::KeepAspectRatio);
			elmt_hotspot = QPoint(
				elmt_hotspot.x() * elmt_pixmap.width() / elmt_pixmap_size.x(),
				elmt_hotspot.y() * elmt_pixmap.height() / elmt_pixmap_size.y()
			);
		}

		drag->setPixmap(elmt_pixmap);
		drag->setHotSpot(elmt_hotspot);
	}

	drag->setMimeData(mime_data);
	drag->exec(Qt::CopyAction);
}
