/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 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,
    libXpertMass::Polymer *polymer,
    /* no libXpertMass::PolChemDef **/
    const QString &configSettingsFilePath,
    const QString &applicationName,
    const QString &description)
    : AbstractSeqEdWndDependentDlg(editorWnd,
                                   polymer,
                                   0, /*polChemDef*/
                                   configSettingsFilePath,
                                   "SequenceEditorFindDlg",
                                   applicationName,
                                   description)
  {
    if(!mp_polymer)
      qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

    if(!initialize())
      qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
  }


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

    // 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;

    // Allocate the motif that we'll be using throughout the life cycle
    // of this dialog window.
    mpa_motif = new libXpertMass::Sequence();
    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()
  {
    delete mpa_motif;
  }


  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();

    mpa_motif->setMonomerText(text);

    if(mpa_motif->makeMonomerList(mp_polymer->getPolChemDefCstSPtr(), true) == -1)
      {
        QMessageBox::warning(this,
                             tr("massXpert - Find Sequence"),
                             tr("%1@%2\n Failed to validate motif: %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(mp_polymer->findForwardMotif(
         mpa_motif, mp_polymer->getPolChemDefCstSPtr(), &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 + mpa_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("massXpert - 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.

        mpa_motif->setMonomerText(text);

        if(mpa_motif->makeMonomerList(mp_polymer->getPolChemDefCstSPtr(), true) ==
           -1)
          {
            QMessageBox::warning(this,
                                 tr("massXpert - Find Sequence"),
                                 tr("%1@%2\n Failed to validate motif: %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(mp_polymer->findForwardMotif(
         mpa_motif, mp_polymer->getPolChemDefCstSPtr(), &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 + mpa_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("massXpert - 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
