/*
 * Copyright (C) 2014-2024 CZ.NIC
 *
 * This program 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 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QFileDialog>
#include <QMessageBox>

#include "src/datovka_shared/identifiers/account_id.h"
#include "src/datovka_shared/log/log.h"
#include "src/dimensions/dimensions.h"
#include "src/global.h"
#include "src/gui/dlg_change_directory.h"
#include "src/io/message_db_set.h"
#include "src/settings/accounts.h"
#include "src/settings/preferences.h"
#include "src/settings/prefs_specific.h"
#include "ui_dlg_change_directory.h"

DlgChangeDirectory::DlgChangeDirectory(const QString &currentDir,
    QWidget *parent)
    : QDialog(parent),
    m_ui(new (::std::nothrow) Ui::DlgChangeDirectory)
{
	m_ui->setupUi(this);
	/* Tab order is defined in UI file. */

	m_ui->newPath->setText("");
	m_ui->currentPath->setText(currentDir);
	m_ui->labelWarning->setStyleSheet("QLabel { color: red }");

	if (m_ui->newPath->text().isEmpty()) {
		m_ui->labelWarning->hide();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
	} else if (m_ui->currentPath->text() != m_ui->newPath->text()) {
		m_ui->labelWarning->hide();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
	} else {
		m_ui->labelWarning->show();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
	}

	connect(m_ui->chooseButton, SIGNAL(clicked()), this,
	    SLOT(chooseNewDirectory(void)));
}

DlgChangeDirectory::~DlgChangeDirectory(void)
{
	delete m_ui;
}

bool DlgChangeDirectory::changeDataDirectory(const AcntId &acntId,
    MessageDbSet *dbSet, QWidget *parent)
{
	if (Q_UNLIKELY((!acntId.isValid()) || (dbSet == Q_NULLPTR))) {
		Q_ASSERT(0);
		return false;
	}

	enum Action action = ACT_MOVE;
	QString newDirPath;

	/* Get current settings. */
	const AcntData itemSettings(GlobInstcs::acntMapPtr->acntData(acntId));

	QString oldDbDir(itemSettings.dbDir());
	if (oldDbDir.isEmpty()) {
		/* Set default directory name. */
		oldDbDir = GlobInstcs::iniPrefsPtr->confDir();
	}

	if (!chooseAction(oldDbDir, newDirPath, action, parent)) {
		return false;
	}

	if (Q_UNLIKELY(newDirPath.isEmpty())) {
		Q_ASSERT(0);
		return false;
	}

	return relocateDatabase(acntId, dbSet, oldDbDir, newDirPath, action,
	    parent);
}

void DlgChangeDirectory::chooseNewDirectory(void)
{
	QString newDir(QFileDialog::getExistingDirectory(this,
	    tr("Open Directory"), QString(),
	    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks));
	m_ui->newPath->setText(newDir);

	if (m_ui->newPath->text().isEmpty()) {
		m_ui->labelWarning->hide();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
	} else if (m_ui->currentPath->text() != m_ui->newPath->text()) {
		m_ui->labelWarning->hide();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
	} else {
		m_ui->labelWarning->show();
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
	}
}

bool DlgChangeDirectory::chooseAction(const QString &currentDir,
    QString &newDir, enum Action &action, QWidget *parent)
{
	DlgChangeDirectory dlg(currentDir, parent);

	const QString dlgName("change_directory");
	const QSize dfltSize = dlg.size();
	{
		const QSize newSize = Dimensions::dialogueSize(&dlg,
		    PrefsSpecific::dlgSize(*GlobInstcs::prefsPtr, dlgName),
		    dfltSize);
		if (newSize.isValid()) {
			dlg.resize(newSize);
		}
	}

	int ret = dlg.exec();

	PrefsSpecific::setDlgSize(*GlobInstcs::prefsPtr, dlgName,
	    dlg.size(), dfltSize);

	if (QDialog::Accepted == ret) {
		newDir = dlg.m_ui->newPath->text();
		if (dlg.m_ui->moveDataRadioButton->isChecked()) {
			action = ACT_MOVE;
		} else if (dlg.m_ui->copyDataRadioButton->isChecked()) {
			action = ACT_COPY;
		} else {
			action = ACT_NEW;
		}
		return true;
	} else {
		return false;
	}
}

bool DlgChangeDirectory::relocateDatabase(const AcntId &acntId,
    MessageDbSet *dbSet, const QString &oldDir, const QString &newDir,
    enum Action action, QWidget *parent)
{
	if (Q_UNLIKELY((!acntId.isValid()) || (dbSet == Q_NULLPTR))) {
		Q_ASSERT(0);
		return false;
	}

	/* Get current settings. */
	AcntData itemSettings(GlobInstcs::acntMapPtr->acntData(acntId));

	switch (action) {
	case ACT_MOVE:
		/* Move account database into new directory. */
		if (dbSet->moveToLocation(newDir)) {
			itemSettings.setDbDir(newDir,
			    GlobInstcs::iniPrefsPtr->confDir());

			logInfo("Database files for '%s' have been moved from '%s' to '%s'.\n",
			    acntId.username().toUtf8().constData(),
			    oldDir.toUtf8().constData(),
			    newDir.toUtf8().constData());

			QMessageBox::information(parent,
			    tr("Change data directory for current data box"),
			    tr("Database files for '%1' have been successfully moved to\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);

			GlobInstcs::acntMapPtr->updateAccount(itemSettings);
			return true;
		} else {
			QMessageBox::critical(parent,
			    tr("Change data directory for current data box"),
			    tr("Database files for '%1' could not be moved to\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);
		}
		break;
	case ACT_COPY:
		/* Copy account database into new directory. */
		if (dbSet->copyToLocation(newDir)) {
			itemSettings.setDbDir(newDir,
			    GlobInstcs::iniPrefsPtr->confDir());

			logInfo("Database files for '%s' have been copied from '%s' to '%s'.\n",
			    acntId.username().toUtf8().constData(),
			    oldDir.toUtf8().constData(),
			    newDir.toUtf8().constData());

			QMessageBox::information(parent,
			    tr("Change data directory for current data box"),
			    tr("Database files for '%1' have been successfully copied to\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);

			GlobInstcs::acntMapPtr->updateAccount(itemSettings);
			return true;
		} else {
			QMessageBox::critical(parent,
			    tr("Change data directory for current data box"),
			    tr("Database files for '%1' could not be copied to\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);
		}
		break;
	case ACT_NEW:
		/* Create a new account database into new directory. */
		if (dbSet->reopenLocation(newDir, MessageDbSet::DO_YEARLY,
		        MessageDbSet::CM_CREATE_EMPTY_CURRENT)) {
			itemSettings.setDbDir(newDir,
			    GlobInstcs::iniPrefsPtr->confDir());

			logInfo("Database files for '%s' have been created in '%s'.\n",
			    acntId.username().toUtf8().constData(),
			    newDir.toUtf8().constData());

			QMessageBox::information(parent,
			    tr("Change data directory for current data box"),
			    tr("New database files for '%1' have been successfully created in\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);

			GlobInstcs::acntMapPtr->updateAccount(itemSettings);
			return true;
		} else {
			QMessageBox::critical(parent,
			    tr("Change data directory for current data box"),
			    tr("New database files for '%1' could not be created in\n\n'%2'.")
			        .arg(acntId.username()).arg(newDir),
			    QMessageBox::Ok);
		}
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	return false;
}
