#include "settings_dialog.hh"
#include "ui_settings_dialog.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QMessageBox>
#include <QFile>
#include <QSqlDatabase>
#include <QSqlError>

namespace {

constexpr char settingsElement[] = "settings";
constexpr char hostnameElement[] = "hostname";
constexpr char databaseElement[] = "database";
constexpr char usernameElement[] = "username";
constexpr char passwordElement[] = "password";

QString serialize(
    const QString& hostname, const QString& database,
    const QString& username, const QString& password)
{
    QString xmlString;
    QXmlStreamWriter xml(&xmlString);

    xml.setAutoFormatting(true);
    xml.writeStartDocument();

    xml.writeStartElement(settingsElement);
    xml.writeTextElement(hostnameElement, hostname);
    xml.writeTextElement(databaseElement, database);
    xml.writeTextElement(usernameElement, username);
    xml.writeTextElement(passwordElement, password);
    xml.writeEndElement();

    xml.writeEndDocument();
    return xmlString;
}

} // namespace

SettingsDialog::SettingsDialog(QWidget* parent) :
    QDialog(parent), ui_(new Ui::SettingsDialog)
{
    ui_->setupUi(this);

    connect(
        ui_->testButton, &QAbstractButton::pressed,
        this, &SettingsDialog::onTestPressed);

    connect(
        ui_->okButton, &QAbstractButton::pressed,
        this, &SettingsDialog::onOkPressed);

    connect(
        ui_->cancelButton, &QAbstractButton::pressed,
        this, &SettingsDialog::onCancelPressed);
}

SettingsDialog::~SettingsDialog()
{
    delete ui_;
}

void SettingsDialog::setSettingsFile(const QString& fileName)
{
    settingsFileName_ = fileName;

    if (!QFile::exists(settingsFileName_)) {
        return;
    }

    QFile file(settingsFileName_);

    if (!file.open(QFile::ReadOnly)){
        QMessageBox::critical(
            this, tr("Error opening settings file"), file.errorString());
        return;
    }

    QXmlStreamReader xml(&file);
    parseSettings(xml);

    fillForm();
}


QString SettingsDialog::hostname() const
{
    return hostname_;
}

QString SettingsDialog::database() const
{
    return database_;
}

QString SettingsDialog::username() const
{
    return username_;
}

QString SettingsDialog::password() const
{
    return password_;
}

void SettingsDialog::fillForm()
{
    ui_->hostnameEdit->setText(hostname_);
    ui_->databaseEdit->setText(database_);
    ui_->usernameEdit->setText(username_);
    ui_->passwordEdit->setText(password_);
}

void SettingsDialog::parseSettings(QXmlStreamReader& xml)
{
    xml.readNextStartElement();

    if (xml.name() != settingsElement)
        return;

    while (xml.readNextStartElement()) {
        if (xml.name() == hostnameElement)
            hostname_ = xml.readElementText();
        else if (xml.name() == databaseElement)
            database_ = xml.readElementText();
        else if (xml.name() == usernameElement)
            username_ = xml.readElementText();
        else if (xml.name() == passwordElement)
            password_ = xml.readElementText();
        else
            xml.skipCurrentElement();
    }
}

void SettingsDialog::saveSettings()
{
    QFile file(settingsFileName_);

    if (!file.open(QFile::WriteOnly)){
        QMessageBox::critical(
            this, QMessageBox::tr("Error opening settings file"),
            file.errorString());
        return;
    }

    auto data = serialize(
        hostname_, database_, username_, password_).toLatin1();

    if (file.write(data) == -1) {
        QMessageBox::critical(
            this, QMessageBox::tr("Error writing settings file"),
            file.errorString());
    }
}

void SettingsDialog::onCancelPressed()
{
    hide();
}

void SettingsDialog::onOkPressed()
{
    hostname_ =  ui_->hostnameEdit->text();
    database_ =  ui_->databaseEdit->text();
    username_ =  ui_->usernameEdit->text();
    password_ =  ui_->passwordEdit->text();

    saveSettings();
    hide();
}

void SettingsDialog::onTestPressed()
{
    {
        QSqlDatabase db =
            QSqlDatabase::addDatabase("QMYSQL", "TestConnection");

        db.setHostName(ui_->hostnameEdit->text());
        db.setDatabaseName(ui_->databaseEdit->text());
        db.setUserName(ui_->usernameEdit->text());
        db.setPassword(ui_->passwordEdit->text());

        if (db.open()) {
            QMessageBox::information(
                this, tr("Connection test"), tr("Connection successful"));
        } else {
            QMessageBox::information(
                this, tr("Connection test"), tr("Connection error: ")
                + db.lastError().text());
        }

        db.close();
    }

    QSqlDatabase::removeDatabase("TestConnection");
}
