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


/////////////////////// Local includes
#include <massxpert/gui/SequenceEditorFindDlg.hpp>


namespace msXpSmassXpert
{

class SequenceEditorWnd;
class SequenceEditorGraphicsView;


SequenceEditorFindDlg::SequenceEditorFindDlg(
  SequenceEditorWnd *editorWnd,
  Polymer *polymer,
  /* no PolChemDef **/
  const QString &configSettingsFilePath)
  : AbstractSeqEdWndDependentDlg(editorWnd,
                                 polymer,
                                 0, /*polChemDef*/
                                 configSettingsFilePath,
                                 "SequenceEditorFindDlg",
                                 "Find in the sequence")
{
  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);

  m_reprocessMotif = false;

  // Allocate the motif that we'll be using throughout the life cycle
  // of this dialog window.
  mpa_motif = new 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->polChemDef(), 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->polChemDef(), &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->polChemDef(), 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->polChemDef(), &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(const QString &text)
{
  m_reprocessMotif = true;
}


} // namespace msXpSmassXpert
