//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#include "smtk/simulation/ace3p/qt/qtNewProjectNamePage.h"

#include "smtk/simulation/ace3p/qt/ui_qtNewProjectNamePage.h"

#include "smtk/simulation/ace3p/JobsManifest.h"

#include <QAbstractButton>
#include <QDebug>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QRegExp>
#include <QString>
#include <QTextStream>
#include <QUuid>

namespace smtk
{
namespace simulation
{
namespace ace3p
{

qtNewProjectNamePage::qtNewProjectNamePage(QWidget* parent)
  : Superclass(parent)
  , ui(new Ui::qtNewProjectNamePage)
  , m_fileDialog(new QFileDialog(this))
{
  this->ui->setupUi(this);

  // Configure file dialog to directory-only mode
  m_fileDialog->setOption(QFileDialog::ShowDirsOnly, true);
  m_fileDialog->setLabelText(QFileDialog::Accept, "Accept");
  m_fileDialog->setFileMode(QFileDialog::DirectoryOnly);
  m_fileDialog->setFilter(QDir::AllDirs);

  this->selectName();

  // Setup fields
  this->registerField("project.name", this->ui->m_nameEdit);
  this->registerField("project.location", this->ui->m_locationEdit);

  // Setup connections
  QObject::connect(
    this->ui->m_browseButton,
    &QAbstractButton::clicked,
    this,
    &qtNewProjectNamePage::browseLocation);
}

void qtNewProjectNamePage::selectName()
{
  this->ui->m_nameEdit->setFocus(Qt::OtherFocusReason);
  this->ui->m_nameEdit->selectAll();
}

QString qtNewProjectNamePage::projectLocation() const
{
  return this->field("project.location").toString();
}

void qtNewProjectNamePage::setProjectLocation(const QString& path)
{
  QString name = this->getUniqueProjectName(path);

  this->setField("project.name", name);
  this->setField("project.location", path);
}

bool qtNewProjectNamePage::validatePage()
{
  // Check the project name
  QString name = this->ui->m_nameEdit->text();
  if (name.isEmpty())
  {
    QMessageBox::critical(this, "Missing Input", "No project name is specified.");
    return false;
  }

  // Check that project name is a valid directory name (sans space char)
  QRegExp regex("^[\\w\\-.]+$");
  if (!regex.exactMatch(name))
  {
    QMessageBox::critical(
      this,
      "Invalid Project Name",
      "Invalid project name."
      " Must only use characters in 0-9, a-z, A-Z, _ (underscore), - (dash), . (period)");
    return false;
  }

  // Check the location
  QString location = this->ui->m_locationEdit->text();
  if (location.isEmpty())
  {
    QMessageBox::critical(this, "Missing Input", "No location is specified.");
    return false;
  }

  // Check that the location/name directory doesn't already exist
  QString path = location + "/" + name;
  if (QDir(path).exists())
  {
    // Directory can be reused IF it contains no remote job records.
    QString manifestPath = path + "/JobsManifest.json";
    if (QFileInfo::exists(manifestPath))
    {
      JobsManifest manifest;
      bool changed = false;
      if (manifest.read(manifestPath.toStdString(), changed) && manifest.size() > 0)
      {
        QString msg = "That project name has already been used to submit remote jobs."
                      " The directory cannot be reused.";
        QMessageBox::critical(this, "Existing Directory", msg);
        return false;
      }
    }

    // OK to reuse directory if current contents can be deleted.
    auto reply = QMessageBox::question(
      this, "Delete existing directory?", "Directory is not empty -- ok to delete?");
    if (reply == QMessageBox::Yes)
    {
      bool deleted = QDir(path).removeRecursively();
      if (!deleted)
      {
        QMessageBox::critical(this, "Delete Failed", "The delete failed for some reason.");
        return false;
      }
    }
  } // if (project path already exists)

  // Update field data
  this->setField("project.name", name);
  this->setField("project.location", location);

  return true;
}

void qtNewProjectNamePage::browseLocation()
{
  m_fileDialog->setDirectory(this->field("project.location").toString());
  int result = m_fileDialog->exec();
  if (result == QDialog::Accepted)
  {
    this->setField("project.location", m_fileDialog->selectedFiles().at(0));
  }
}

QString qtNewProjectNamePage::getUniqueProjectName(const QString& location) const
{
  QDir qdir;
  QString name;
  for (unsigned n = 1; n < 100; ++n)
  {
    name = QString("project%1").arg(n);
    QString path = QString("%1/%2").arg(location, name);
    if (!qdir.exists(path))
    {
      return name;
    }
  }

  // else
  qWarning() << "project numbers 1-99 already used; switching to UUIDs";
  name = QUuid::createUuid().toString();
  return name;
}

} // namespace ace3p
} // namespace simulation
} // namespace smtk
