/* BEGIN software license
 *
 * MsXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2026 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
 */


/////////////////////// Qt includes
#include <QMessageBox>
#include <QSettings>


/////////////////////// Local includes
#include "SequenceEditorFindDlg.hpp"


namespace MsXpS
{

namespace MassXpert
{


class SequenceEditorWnd;
class SequenceEditorGraphicsView;


SequenceEditorFindDlg::SequenceEditorFindDlg(
  SequenceEditorWnd *editorWnd,
  libXpertMassCore::PolymerQSPtr polymer_sp,
  /* no libXpertMassCore::PolChemDef **/
  const QString &configSettingsFilePath,
  const QString &application_name,
  const QString &description)
  : AbstractSeqEdWndDependentDlg(editorWnd,
                                 polymer_sp,
                                 0, /*polChemDef*/
                                 configSettingsFilePath,
                                 "SequenceEditorFindDlg",
                                 application_name,
                                 description)
{
  if(polymer_sp == nullptr)
    qFatal() << "Programming error. Pointer cannot be nullptr";

  if(polymer_sp->getPolChemDefCstSPtr() == nullptr)
    qFatal() << "Programming error. Pointer cannot be nullptr";

  m_motif.setPolChemDefCstSPtr(polymer_sp->getPolChemDefCstSPtr());

  if(!initialize())
    qFatal()
      << "Programming error. Failed to initialize the dialog window.";
}


bool
SequenceEditorFindDlg::initialize()
{
  m_ui.setupUi(this);

  setWindowIcon(qApp->windowIcon());

  // Update the window title because the window title element in m_ui might be
  // either erroneous or empty.
  setWindowTitle(
    QString("%1 - %2").arg(m_applicationName).arg(m_windowDescription));

  m_reprocessMotif = false;

  m_ui.motifToFindComboBox->addItems(m_history);
  m_ui.motifToFindComboBox->insertItem(0, "");
  m_ui.motifToFindComboBox->setCurrentIndex(0);

  readSettings();

  connect(m_ui.findPushButton, SIGNAL(clicked()), this, SLOT(find()));

  connect(m_ui.nextPushButton, SIGNAL(clicked()), this, SLOT(next()));

  connect(m_ui.motifToFindComboBox,
          SIGNAL(editTextChanged(const QString &)),
          this,
          SLOT(motifComboBoxEditTextChanged(const QString &)));

  connect(
    m_ui.clearHistoryPushButton, SIGNAL(clicked()), this, SLOT(clearHistory()));

  return true;
}


SequenceEditorFindDlg::~SequenceEditorFindDlg()
{
}


void
SequenceEditorFindDlg::writeSettings()
{
  QSettings settings(m_configSettingsFilePath, QSettings::IniFormat);
  settings.beginGroup(m_wndTypeName);
  settings.setValue("geometry", saveGeometry());
  settings.setValue("history", m_history);
  settings.endGroup();
}

void
SequenceEditorFindDlg::readSettings()
{
  QSettings settings(m_configSettingsFilePath, QSettings::IniFormat);
  settings.beginGroup(m_wndTypeName);
  restoreGeometry(settings.value("geometry").toByteArray());
  m_history = settings.value("history").toStringList();
  settings.endGroup();
}


void
SequenceEditorFindDlg::clearHistory()
{
  m_history.clear();
  m_ui.motifToFindComboBox->clear();

  QSettings settings(m_configSettingsFilePath, QSettings::IniFormat);
  settings.beginGroup(m_wndTypeName);
  settings.setValue("history", m_history);
  settings.endGroup();
}

void
SequenceEditorFindDlg::find()
{
  // First we should validate the sequence to search. Is it correct ?

  // Create a sequence in which we'll set the text of the line edit
  // and we'll ask to make a monomer list with it.

  QString text = m_ui.motifToFindComboBox->currentText();

  std::vector<std::size_t> failing_indices;
  m_motif.setSequence(text, failing_indices);

  if(failing_indices.size())
    {
      QMessageBox::warning(
        this,
        tr("MassXpert3 - Find sequence"),
        tr("%1@%2\n Failed to validate the searched sequence: %3")
          .arg(__FILE__)
          .arg(__LINE__)
          .arg(text));
      return;
    }

  // At this point we have a valid motif.

  // Prepend that motif to the history and to the comboBox.
  if(!m_history.contains(text))
    {
      m_history.prepend(text);
      m_ui.motifToFindComboBox->insertItem(0 + 1, text);
    }

  // And now search for that motif in the polymer sequence.

  m_startSearchIndex = 0;

  if(msp_polymer->getSequenceCstRef().findForwardMotif(m_motif,
                                                       m_startSearchIndex) == 1)
    {
      // A motif was successfully found, index now contains the value
      // corresponding to the index of the first monomer in the
      // polymer sequence that matched the sequence. We should
      // highlight the sequence that was found, between
      // [m_startSearchIndex and m_startSearchIndex + motif->size - 1]

      // For example, polymer is:

      // MAMISGMSGRKAS

      // and motif is SGR

      // m_startSearchIndex is 4(fifth monomer) and thus the end index
      // is [4 + 3 -1] that is 6.

      // Set the selection to that interval in the polymer sequence
      // editor graphics view.

      m_endSearchIndex = m_startSearchIndex + m_motif.size() - 1;

      mp_editorWnd->mpa_editorGraphicsView->setSelection(
        m_startSearchIndex, m_endSearchIndex, false, false);

      // Before returning, increment the m_startSearchIndex by one
      // unit, so that when the user clicks next, we'll not fall on
      // the same polymer sequence.

      ++m_startSearchIndex;

      m_reprocessMotif = false;

      return;
    }
  else
    QMessageBox::warning(this,
                         tr("MassXpert3 - Find Sequence"),
                         tr("Failed to find sequence motif: %1").arg(text));
}


void
SequenceEditorFindDlg::next()
{
  QString text = m_ui.motifToFindComboBox->currentText();

  // Only reprocess the motif if required.
  if(m_reprocessMotif)
    {
      // First we should validate the sequence to search. Is it correct ?

      // Create a sequence in which we'll set the text of the line edit
      // and we'll ask to make a monomer list with it.

      std::vector<std::size_t> failing_indices;
      m_motif.setSequence(text, failing_indices);

      if(failing_indices.size())
        {
          QMessageBox::warning(
            this,
            tr("MassXpert3 - Find sequence"),
            tr("%1@%2\n Failed to validate the searched sequence: %3")
              .arg(__FILE__)
              .arg(__LINE__)
              .arg(text));
          return;
        }
    }

  // At this point, we can perform the search, at the last index value
  // set by last find() call.

  if(msp_polymer->getSequenceCstRef().findForwardMotif(m_motif,
                                                       m_startSearchIndex) == 1)
    {
      // A motif was successfully found, index now contains the value
      // corresponding to the index of the first monomer in the
      // polymer sequence that matched the sequence. We should
      // highlight the sequence that was found, between
      // [m_startSearchIndex and m_startSearchIndex + motif->size - 1]

      // For example, polymer is:

      // MAMISGMSGRKAS

      // and motif is SGR

      // m_startSearchIndex is 4(fifth monomer) and thus the end index
      // is [4 + 3 -1] that is 6.

      // Set the selection to that interval in the polymer sequence
      // editor graphics view.

      m_endSearchIndex = m_startSearchIndex + m_motif.size() - 1;

      mp_editorWnd->mpa_editorGraphicsView->setSelection(
        m_startSearchIndex, m_endSearchIndex, false, false);

      // Before returning, increment the m_startSearchIndex by one
      // unit, so that when the user clicks next, we'll not fall on
      // the same polymer sequence.

      ++m_startSearchIndex;

      return;
    }
  else
    QMessageBox::warning(this,
                         tr("MassXpert3 - Find Sequence"),
                         tr("Failed to find sequence motif: %1").arg(text));
}


void
SequenceEditorFindDlg::motifComboBoxEditTextChanged(
  [[maybe_unused]] const QString &text)
{
  m_reprocessMotif = true;
}


} // namespace MassXpert

} // namespace MsXpS
