/* BEGIN software license
 *
 * MsXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright (C) 2009--2020 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the MsXpertSuite project.
 *
 * The MsXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * 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/>.
 *
 * END software license
 */

/////////////////////// Std lib includes

/////////////////////// Qt includes
#include <QDialog>
#include <QPushButton>
#include <QTimer>
#include <QSettings>


/////////////////////// Local includes
#include "MsXpS/libXpertMassCore/Utils.hpp"
#include "MsXpS/libXpertMassGui/MassDataClientServerConfigDlg.hpp"

#include "ui_MassDataClientServerConfigDlg.h"

namespace MsXpS
{

namespace libXpertMassGui
{


/*!
\class MsXpS::libXpertMassGui::MassDataClientServerConfigDlg
\inmodule libXpertMassGui
\ingroup XpertMassGuiUtilities
\inheaderfile MassDataClientServerConfigDlg.hpp

\brief The MassDataClientServerConfigDlg class provides a mass data
client-server network connection configuration dialog window.
*/


/*!
\variable MsXpS::libXpertMassGui::MassDataClientServerConfigDlg::mp_ui

\brief The graphical user interface definition.
*/

/*!
\variable \
MsXpS::libXpertMassGui::MassDataClientServerConfigDlg::m_applicationName

\brief The name of the application.
*/

/*!
\variable \
MsXpS::libXpertMassGui::MassDataClientServerConfigDlg::mp_programWindow

\brief The main program window.
*/


/*!
\brief Constructs a MassDataClientServerConfigDlg instance.

\list
\li \a program_window_p: the program's main window.
\li \a applicationName: the name of the application, typically massXpert3 or
mineXpert3, for example.
\li \a description: the string describing what this dialog window is for (used
for the window title).
\li \a server_ip_config: a pair of values, IP address as a string and port
number as an integer.
\endlist
*/
MassDataClientServerConfigDlg::MassDataClientServerConfigDlg(
  QWidget *program_window_p,
  const QString &applicationName,
  const QString &description,
  std::pair<QString, int> server_ip_config)
  : QDialog(program_window_p),
    m_applicationName{applicationName},
    mp_programWindow(program_window_p),
    m_serverIpConfig(server_ip_config),
    mp_ui(new Ui::MassDataClientServerConfigDlg)
{
  if(!program_window_p)
    qFatal("Programming error.");

  mp_ui->setupUi(this);

  // Update the window title because the window title element in mp_ui->might be
  // either erroneous or empty.
  setWindowTitle(QString("%1 - %2").arg(applicationName).arg(description));

  //// We want to destroy the dialog when it is closed.
  // setAttribute(Qt::WA_DeleteOnClose);

  if(!server_ip_config.first.isEmpty())
    mp_ui->localServerIpAddressLineEdit->setText(server_ip_config.first);
  else if(!m_serverIpConfig.first.isEmpty())
    mp_ui->localServerIpAddressLineEdit->setText(m_serverIpConfig.first);

  if(server_ip_config.second != 0)
    mp_ui->localServerPortNumberLineEdit->setText(
      QString("%1").arg(server_ip_config.second));
  else if(m_serverIpConfig.second != 0)
    mp_ui->localServerPortNumberLineEdit->setText(
      QString("%1").arg(m_serverIpConfig.second));

  // Perform all the connections.

  // Typically, the user of startServerSignal is ProgramWindow that created this
  // dialog window.
  connect(mp_ui->startServerPushButton, &QPushButton::clicked, this, [this]() {
    emit startServerSignal();
  });

  // Typically, the user of stopServerSignal is ProgramWindow that created this
  connect(mp_ui->stopServerPushButton, &QPushButton::clicked, this, [this]() {
    emit stopServerSignal();
  });

  connect(mp_ui->startClientPushButton,
          &QPushButton::clicked,
          this,
          &MassDataClientServerConfigDlg::startClient);

  connect(mp_ui->stopClientPushButton, &QPushButton::clicked, this, [this]() {
    emit stopClientSignal();
  });

  connect(mp_ui->clearRemoteIpAddressPushButton,
          &QPushButton::clicked,
          this,
          [this]() {
            mp_ui->remoteServerIpAddressComboBox->removeItem(
              mp_ui->remoteServerIpAddressComboBox->currentIndex());
          });

  connect(mp_ui->clearRemotePortNumberPushButton,
          &QPushButton::clicked,
          this,
          [this]() {
            mp_ui->remoteServerPortNumberComboBox->removeItem(
              mp_ui->remoteServerPortNumberComboBox->currentIndex());
          });

  readSettings(
    MsXpS::libXpertMassCore::Utils::configSettingsFilePath);
}

/*!
\brief Destructs this MassDataClientServerConfigDlg instance.
*/
MassDataClientServerConfigDlg::~MassDataClientServerConfigDlg()
{
  writeSettings(
    MsXpS::libXpertMassCore::Utils::configSettingsFilePath);
}

/*!
\brief Does not close the window, just hides it (\a event is not used).
*/
void
MassDataClientServerConfigDlg::closeEvent([[maybe_unused]] QCloseEvent *event)
{
  qDebug();
  hide();
}

/*!
\brief Writes the settings of the dialog window to \a config_settings_file_path
for later restoration.
*/
void
MassDataClientServerConfigDlg::writeSettings(
  const QString &config_settings_file_path)
{
  // qDebug();

  QSettings settings(config_settings_file_path, QSettings::IniFormat);

  settings.beginGroup("MassDataClientServerConfigDlg");

  settings.setValue("geometry", saveGeometry());

  // Save the remove server IP history list from the combo box.

  QStringList items;

  for(int iter = 0; iter < mp_ui->remoteServerIpAddressComboBox->count();
      ++iter)
    items.append(mp_ui->remoteServerIpAddressComboBox->itemText(iter));

  settings.setValue("remote_server_ip_addresses", items);

  items.clear();

  for(int iter = 0; iter < mp_ui->remoteServerPortNumberComboBox->count();
      ++iter)
    items.append(mp_ui->remoteServerPortNumberComboBox->itemText(iter));

  settings.setValue("remote_server_port_numbers", items);

  // Retrieve QStringList
  QStringList retrievedList = settings.value("myList").toStringList();


  settings.endGroup();
}

/*!
\brief Reads the settings of this dialog window from \a
config_settings_file_path.
*/
void
MassDataClientServerConfigDlg::readSettings(
  const QString &config_settings_file_path)
{
  // qDebug();

  QSettings settings(config_settings_file_path, QSettings::IniFormat);

  settings.beginGroup("MassDataClientServerConfigDlg");

  restoreGeometry(settings.value("geometry").toByteArray());

  // Retrieve the IP addresses
  QStringList items =
    settings.value("remote_server_ip_addresses").toStringList();

  if(items.size())
    {

      foreach(QString item, items)
        mp_ui->remoteServerIpAddressComboBox->addItem(item);

      mp_ui->remoteServerIpAddressComboBox->setCurrentText(items.last());

      items.clear();
    }

  // Retrieve the port numbers
  items = settings.value("remote_server_port_numbers").toStringList();

  if(items.size())
    {
      foreach(QString item, items)
        mp_ui->remoteServerPortNumberComboBox->addItem(item);

      mp_ui->remoteServerPortNumberComboBox->setCurrentText(items.last());
    }
  settings.endGroup();
}

void
MassDataClientServerConfigDlg::updateServerIpData(
  std::pair<QString, int> server_ip_config)
{
  m_serverIpConfig = server_ip_config;

  mp_ui->localServerIpAddressLineEdit->setText(m_serverIpConfig.first);
  mp_ui->localServerPortNumberLineEdit->setText(
    QString("%1").arg(m_serverIpConfig.second));
}

void
MassDataClientServerConfigDlg::updateClientIpData(
  std::pair<QString, int> client_ip_config)
{
  m_clientIpConfig = client_ip_config;
  mp_ui->remoteServerIpAddressComboBox->addItem(m_clientIpConfig.first);
  mp_ui->remoteServerPortNumberComboBox->addItem(
    QString("%1").arg(m_clientIpConfig.second));
}

/*!
\brief Starts the client using the configuration entered in the dialog window.
*/
void
MassDataClientServerConfigDlg::startClient()
{
  // We need to know what is the requested configuration.

  QString ip_address = mp_ui->remoteServerIpAddressComboBox->currentText();

  if(ip_address.isEmpty())
    {
      message("Please, configure the remote server IP address.");
      return;
    }

  QString port_number_string =
    mp_ui->remoteServerPortNumberComboBox->currentText();

  if(port_number_string.isEmpty())
    {
      message("Please, configure the remote server port number");
      return;
    }

  bool ok         = false;
  int port_number = port_number_string.toInt(&ok);

  if(!ok)
    {
      message(
        "Please, configure the remote server port number (that should be an "
        "integer)");
      return;
    }

  m_clientIpConfig = std::pair<QString, int>(ip_address, port_number);

  qDebug() << "Asking that a client be started to connect to a remote server:"
           << ip_address << ":" << port_number;

  // Typically the user of startClientSignal is ProgramWindow that created this
  // dialog window.
  emit startClientSignal(ip_address, port_number);
}

/*!
\brief Writes the \a message to the message line edit widget.

After \a timeout milliseconds, the message is erased. By default that timeout is
3000 ms.
*/
void
MassDataClientServerConfigDlg::message(const QString &message, int timeout)
{
  if(mp_ui->messageLineEdit->text() == message)
    return;

  mp_ui->messageLineEdit->setText(message);
  QTimer::singleShot(timeout, [this]() {
    mp_ui->messageLineEdit->setText("");
  });
}

/*!
\brief Update the client configuration on the basis of \a ip_address and \a
port_number. This is the configuration of the server to which this client
will connect.
*/
void
MassDataClientServerConfigDlg::updateClientConfigurationData(
  const QString &ip_address, int port_number)
{
  mp_ui->localServerIpAddressLineEdit->setText(ip_address);
  mp_ui->localServerPortNumberLineEdit->setText(QString::number(port_number));
}

/*!
\brief Writes the \a error to the message line edit widget.

After a imeout of 10 seconds, the message is erased.
*/
void
MassDataClientServerConfigDlg::clientFailingFeedback(const QString &error)
{
  qDebug();
  message(error, 10000);
}

void
MassDataClientServerConfigDlg::registerJsConstructor(QJSEngine *engine)

{
  if(!engine)
    {
      qDebug() << "Cannot register MassDataClientServerConfigDlg class: "
                  "engine is null";
      return;
    }

  // Register the meta object as a constructor

  QJSValue jsMetaObject =
    engine->newQMetaObject(&MassDataClientServerConfigDlg::staticMetaObject);
  engine->globalObject().setProperty("MassDataClientServerConfigDlg",
                                     jsMetaObject);
}


} // namespace libXpertMassGui
} // namespace MsXpS
