/*
	File                 : ImportSQLDatabaseDialog.cpp
	Project              : LabPlot
	Description          : import SQL dataase dialog
	--------------------------------------------------------------------
	SPDX-FileCopyrightText: 2016-2023 Alexander Semke <alexander.semke@web.de>
	SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "ImportSQLDatabaseDialog.h"
#include "ImportSQLDatabaseWidget.h"
#include "backend/core/Settings.h"
#include "backend/core/Workbook.h"
#include "backend/lib/macros.h"
#include "backend/matrix/Matrix.h"
#include "backend/spreadsheet/Spreadsheet.h"
#include "frontend/widgets/TreeViewComboBox.h"
#include "frontend/MainWin.h"

#include <QDialogButtonBox>
#include <QElapsedTimer>
#include <QProgressBar>
#include <QStatusBar>
#include <QWindow>

#include <KLocalizedString>
#include <KWindowConfig>

/*!
	\class ImportSQLDatabaseDialog
	\brief Dialog for importing data from a SQL database. Embeds \c ImportSQLDatabaseWidget and provides the standard buttons.

	\ingroup frontend
 */
ImportSQLDatabaseDialog::ImportSQLDatabaseDialog(MainWin* parent)
	: ImportDialog(parent)
	, importSQLDatabaseWidget(new ImportSQLDatabaseWidget(this)) {
	vLayout->addWidget(importSQLDatabaseWidget);

	setWindowTitle(i18nc("@title:window", "Import Data to Spreadsheet or Matrix"));
	setWindowIcon(QIcon::fromTheme(QStringLiteral("document-import-database")));
	setModel();

	// dialog buttons
	auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	okButton = buttonBox->button(QDialogButtonBox::Ok);
	okButton->setEnabled(false); // ok is only available if a valid container was selected
	vLayout->addWidget(buttonBox);

	// Signals/Slots
	connect(importSQLDatabaseWidget, &ImportSQLDatabaseWidget::stateChanged, this, &ImportSQLDatabaseDialog::checkOkButton);
	connect(importSQLDatabaseWidget, &ImportSQLDatabaseWidget::error, this, &ImportSQLDatabaseDialog::showErrorMessage);
	connect(buttonBox, &QDialogButtonBox::accepted, this, &ImportDialog::accept);
	connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

	// restore saved settings if available
	create(); // ensure there's a window created
	KConfigGroup conf = Settings::group(QStringLiteral("ImportSQLDatabaseDialog"));
	if (conf.exists()) {
		KWindowConfig::restoreWindowSize(windowHandle(), conf);
		resize(windowHandle()->size()); // workaround for QTBUG-40584
	} else
		resize(QSize(0, 0).expandedTo(minimumSize()));
}

ImportSQLDatabaseDialog::~ImportSQLDatabaseDialog() {
	// save current settings
	KConfigGroup conf = Settings::group(QStringLiteral("ImportSQLDatabaseDialog"));
	KWindowConfig::saveWindowSize(windowHandle(), conf);
}

bool ImportSQLDatabaseDialog::importTo(QStatusBar* statusBar) const {
	DEBUG("ImportSQLDatabaseDialog::import()");
	AbstractAspect* aspect = static_cast<AbstractAspect*>(cbAddTo->currentModelIndex().internalPointer());
	if (!aspect) {
		DEBUG("ERROR: No aspect available!");
		return false;
	}

	const auto mode = AbstractFileFilter::ImportMode(cbPosition->currentIndex());

	// show a progress bar in the status bar
	auto* progressBar = new QProgressBar();
	progressBar->setMinimum(0);
	progressBar->setMaximum(100);
	connect(importSQLDatabaseWidget, &ImportSQLDatabaseWidget::completed, progressBar, &QProgressBar::setValue);

	statusBar->clearMessage();
	statusBar->addWidget(progressBar, 1);

	WAIT_CURSOR;
	QApplication::processEvents(QEventLoop::AllEvents, 100);

	// TODO: error handling
	QElapsedTimer timer;
	timer.start();
	if (aspect->inherits(AspectType::Matrix)) {
		auto* matrix = qobject_cast<Matrix*>(aspect);
		importSQLDatabaseWidget->read(matrix, mode);
	} else if (aspect->inherits(AspectType::Spreadsheet)) {
		auto* spreadsheet = qobject_cast<Spreadsheet*>(aspect);
		importSQLDatabaseWidget->read(spreadsheet, mode);
	} else if (aspect->inherits(AspectType::Workbook)) {
		// use active spreadsheet or matrix (only if numeric data is going to be imported) if present,
		// create a new spreadsheet in the selected workbook otherwise
		auto* workbook = qobject_cast<Workbook*>(aspect);
		Spreadsheet* spreadsheet = workbook->currentSpreadsheet();
		Matrix* matrix = workbook->currentMatrix();
		if (spreadsheet)
			importSQLDatabaseWidget->read(spreadsheet, mode);
		else if (matrix && importSQLDatabaseWidget->isNumericData())
			importSQLDatabaseWidget->read(matrix, mode);
		else {
			spreadsheet = new Spreadsheet(i18n("Spreadsheet"));
			workbook->addChild(spreadsheet);
			importSQLDatabaseWidget->read(spreadsheet, mode);
		}
	}
	statusBar->showMessage(i18n("Data imported in %1 seconds.", (float)timer.elapsed() / 1000));

	RESET_CURSOR;
	statusBar->removeWidget(progressBar);
	return true;
}

QString ImportSQLDatabaseDialog::selectedObject() const {
	return importSQLDatabaseWidget->selectedTable();
}

void ImportSQLDatabaseDialog::checkOkButton() {
	DEBUG("ImportSQLDatabaseDialog::checkOkButton()");

	AbstractAspect* aspect = static_cast<AbstractAspect*>(cbAddTo->currentModelIndex().internalPointer());
	if (!aspect) {
		okButton->setEnabled(false);
		okButton->setToolTip(i18n("Select a data container where the data has to be imported into."));
		cbPosition->setEnabled(false);
		return;
	}

	// check whether a valid connection and an object to import were selected
	if (!importSQLDatabaseWidget->isValid()) {
		okButton->setEnabled(false);
		okButton->setToolTip(i18n("Select a valid database object (table or query result set) that has to be imported."));
		cbPosition->setEnabled(false);
		return;
	}

	// for matrix containers allow to import only numerical data
	if (dynamic_cast<const Matrix*>(aspect) && !importSQLDatabaseWidget->isNumericData()) {
		okButton->setEnabled(false);
		okButton->setToolTip(i18n("Cannot import into a matrix since the data contains non-numerical data."));
		cbPosition->setEnabled(false);
		return;
	}

	okButton->setEnabled(true);
	okButton->setToolTip(i18n("Close the dialog and import the data."));
	cbPosition->setEnabled(true);
}
