//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Widget/FileDialog4Project.cpp
//! @brief     Implements class FileDialog4Project.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/View/Widget/FileDialog4Project.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/Model/Project/ProjectUtil.h"
#include "GUI/View/Widget/AppConfig.h"
#include <QFileDialog>
#include <QGroupBox>
#include <QPushButton>
#include <QVBoxLayout>

FileDialog4Project::FileDialog4Project(QWidget* parent, const QString& workingDirectory,
                                       const QString& projectName)
    : QDialog(parent)
    , m_project_name_edit(new QLineEdit)
    , m_work_dir_edit(new QLineEdit)
    , m_browse_button(nullptr)
    , m_warning_label(new QLabel)
    , m_cancel_button(nullptr)
    , m_create_button(nullptr)
    , m_valid_project_name(true)
    , m_valid_project_path(true)

{
    setMinimumSize(480, 280);
    setWindowTitle("Save project");

    auto* nameLabel = new QLabel("Project name:");

    m_project_name_edit->setText(projectName);
    connect(m_project_name_edit, &QLineEdit::textEdited, this,
            &FileDialog4Project::checkIfProjectNameIsValid);
    nameLabel->setBuddy(m_project_name_edit);

    auto* parentDirLabel = new QLabel("Save in:");

    m_work_dir_edit->setText(QDir::toNativeSeparators(QDir::homePath()));
    connect(m_work_dir_edit, &QLineEdit::textEdited, this,
            &FileDialog4Project::checkIfProjectPathIsValid);
    parentDirLabel->setBuddy(m_work_dir_edit);

    m_browse_button = new QPushButton("Browse");
    connect(m_browse_button, &QPushButton::clicked, this, &FileDialog4Project::onBrowseDirectory);

    m_create_button = new QPushButton("Save");
    connect(m_create_button, &QPushButton::clicked, this, &FileDialog4Project::createProjectDir);
    m_create_button->setDefault(true);
    m_cancel_button = new QPushButton("Cancel");
    connect(m_cancel_button, &QPushButton::clicked, this, &FileDialog4Project::reject);

    auto* projectGroup = new QGroupBox("Project name and location");

    auto* layout = new QGridLayout;
    layout->addWidget(nameLabel, 0, 0);
    layout->addWidget(m_project_name_edit, 0, 1);
    layout->addWidget(parentDirLabel, 1, 0);
    layout->addWidget(m_work_dir_edit, 1, 1);
    layout->addWidget(m_browse_button, 1, 2);

    projectGroup->setLayout(layout);

    auto* buttonsLayout = new QHBoxLayout;
    buttonsLayout->addStretch(1);
    buttonsLayout->addWidget(m_create_button);
    buttonsLayout->addWidget(m_cancel_button);

    auto* mainLayout = new QVBoxLayout;
    mainLayout->addWidget(projectGroup);
    mainLayout->addWidget(m_warning_label);
    mainLayout->addStretch();
    mainLayout->addLayout(buttonsLayout);

    setLayout(mainLayout);

    setWorkingDirectory(workingDirectory);
}

QString FileDialog4Project::getWorkingDirectory() const
{
    return QDir::fromNativeSeparators(m_work_dir_edit->text());
}

void FileDialog4Project::setWorkingDirectory(const QString& text)
{
    m_work_dir_edit->setText(QDir::toNativeSeparators(text));
}

QString FileDialog4Project::getProjectFileName() const
{
    QString projectDir = getWorkingDirectory() + QString("/") + getProjectName();
    QString projectFile = getProjectName() + GUI::Util::Project::projectFileExtension;
    return projectDir + QString("/") + projectFile;
}

//! calls directory selection dialog
void FileDialog4Project::onBrowseDirectory()
{
    QFileDialog::Options options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly;

    const QString dirname =
        QFileDialog::getExistingDirectory(this, "Select directory", getWorkingDirectory(), options);

    if (dirname.isEmpty())
        return;

    checkIfProjectPathIsValid(dirname);
    checkIfProjectNameIsValid(getProjectName());
}

//! Checks whether ProjectPath is valid and sets warning state accordingly. Corresponding directory
//! should exists.
void FileDialog4Project::checkIfProjectPathIsValid(const QString& dirname)
{
    if (QFile::exists(dirname)) {
        setValidProjectPath(true);
        setWorkingDirectory(dirname);
    } else {
        setValidProjectPath(false);
    }
    updateWarningStatus();
}

//! Checks whether project name is valid and sets warning state accordingly. There should not be the
//! directory with such name in ProjectPath
void FileDialog4Project::checkIfProjectNameIsValid(const QString& projectName)
{
    const QDir projectDir = getWorkingDirectory() + "/" + projectName;
    setValidProjectName(!projectDir.exists());
    updateWarningStatus();
}

//! sets flags whether project name is valid and then updates color of LineEdit
//! and warning message
void FileDialog4Project::setValidProjectName(bool status)
{
    m_valid_project_name = status;
    QPalette palette;
    palette.setColor(QPalette::Text, m_valid_project_path ? Qt::black : Qt::darkRed);
    m_project_name_edit->setPalette(palette);
}

//! sets flags wether project path is valid and then updates color of LineEdit
//! and warning message
void FileDialog4Project::setValidProjectPath(bool status)
{
    m_valid_project_path = status;
    QPalette palette;
    palette.setColor(QPalette::Text, m_valid_project_path ? Qt::black : Qt::darkRed);
    m_work_dir_edit->setPalette(palette);
}

//! updates warning label depending on validity of project name and path
void FileDialog4Project::updateWarningStatus()
{
    if (m_valid_project_path && m_valid_project_name) {
        m_create_button->setEnabled(true);
        m_warning_label->setText("");
    } else if (!m_valid_project_path) {
        m_create_button->setEnabled(false);
        m_warning_label->setText("<font color='darkRed'> The path '"
                                 + QDir::toNativeSeparators(getWorkingDirectory())
                                 + "' does not exist. </font>");
    } else if (!m_valid_project_name) {
        m_create_button->setEnabled(false);
        if (getProjectName().isEmpty())
            m_warning_label->setText("<font color='darkRed'> Please specify project name. </font>");
        else {
            m_warning_label->setText("<font color='darkRed'> The directory '" + getProjectName()
                                     + "' already exists. </font>");
        }
    }
}

//! creates directory with selected ProjectName in selected ProjectPath
void FileDialog4Project::createProjectDir()
{
    QDir parentDir = getWorkingDirectory();
    if (!parentDir.mkdir(getProjectName())) {
        m_warning_label->setText("<font color='darkRed'> Cannot make subdirectory' '"
                                 + getProjectName() + "' in '"
                                 + QDir::toNativeSeparators(getWorkingDirectory()) + "' </font>");
    } else {
        accept();
    }
}
