/* 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 <massxpert/gui/PolymerModificationDlg.hpp>


namespace msXpSmassXpert
{

PolymerModificationDlg::PolymerModificationDlg(SequenceEditorWnd *editorWnd,
                                               /* no polymer **/
                                               /* no PolChemDef **/
                                               const QString &settingsFilePath,
                                               PolymerEnd end)
  : AbstractSeqEdWndDependentDlg(editorWnd,
                                 0, /*polymer **/
                                 0, /*polChemDef **/
                                 settingsFilePath,
                                 "PolymerModificationDlg",
                                 "Polymer modification"),
    m_polymerEnd{end}
{
  if(!initialize())
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
}


PolymerModificationDlg::~PolymerModificationDlg()
{
}


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

  populateModificationList();

  if(mp_editorWnd)
    updateModificationLineEdits();


  if(m_polymerEnd & END_LEFT)
    m_ui.leftEndCheckBox->setChecked(true);

  if(m_polymerEnd & END_RIGHT)
    m_ui.rightEndCheckBox->setChecked(true);

  readSettings();

  connect(this, SIGNAL(rejected()), this, SLOT(close()));

  connect(m_ui.modifyPushButton, SIGNAL(clicked()), this, SLOT(modify()));

  connect(m_ui.unmodifyPushButton, SIGNAL(clicked()), this, SLOT(unmodify()));

  return true;
}


void
PolymerModificationDlg::updateModificationLineEdits()
{
  Polymer *polymer = mp_editorWnd->polymer();

  m_ui.leftEndLineEdit->setText(QString("%1 = %2")
                                  .arg(polymer->leftEndModif().formula())
                                  .arg(polymer->leftEndModif().name()));

  m_ui.rightEndLineEdit->setText(QString("%1 = %2")
                                   .arg(polymer->rightEndModif().formula())
                                   .arg(polymer->rightEndModif().name()));
}


bool
PolymerModificationDlg::populateModificationList()
{
  PolChemDef *polChemDef = mp_editorWnd->polChemDef();
  Q_ASSERT(polChemDef);

  for(int iter = 0; iter < polChemDef->modifList().size(); ++iter)
    {
      Modif *modif = polChemDef->modifList().at(iter);
      Q_ASSERT(modif);

      m_ui.modifListWidget->addItem(modif->name());
    }

  return true;
}


bool
PolymerModificationDlg::parseModifDefinition(Modif *modif)
{
  Q_ASSERT(modif);

  QString text = m_ui.modifNameLineEdit->text();

  modif->setName(text);

  text = m_ui.modifFormulaLineEdit->text();

  modif->setFormula(text);

  // Attention, we have to compute the masses of the modif !

  if(!modif->calculateMasses())
    return false;

  // We do not actually care of the targets of the modification. This
  // member datum should be '*' by default anyway.

  //  modif->setTargets("*");

  if(!modif->validate())
    return false;

  return true;
}


void
PolymerModificationDlg::modify()
{
  Polymer *polymer = mp_editorWnd->polymer();

  // There are two ways to perform a modification: either select one
  // modification from the list of available modifications as defined
  // in the polymer chemistry definition, or perform a quick and dirty
  // modification definition in the dialog.

  Modif modif(polymer->polChemDef(), "NOT_SET");

  if(m_ui.defineModifGroupBox->isChecked())
    {
      // The user wants to use a self-defined modification.

      if(!parseModifDefinition(&modif))
        {
          return;
        }
    }
  else
    {
      // The user should have selected one item from the list of
      // available modifications. Let's get to the modification in
      // question.

      QList<QListWidgetItem *> selectedList =
        m_ui.modifListWidget->selectedItems();

      if(selectedList.size() != 1)
        return;

      QString text = selectedList.at(0)->text();
      Q_ASSERT(!text.isEmpty());
      //       qDebug() << __FILE__ << __LINE__
      // 		<< "Selected modif:" << text;

      // Change modif so that it has its name, and we can ask the
      // polymer chemistry definition to fully qualify it by its name.

      modif.setName(text);

      // Find the proper modification in the list of modifs in the
      // polymer chemistry definition and update all the data from the
      // reference one in the polymer chemistry definition.
      if(Modif::isNameInList(
           text, polymer->polChemDef()->modifList(), &modif) == -1)
        {
          QMessageBox::warning(
            this,
            tr("massXpert - Polymer Modification"),
            tr("Failed to find formula(%1) in list.").arg(modif.name()),
            QMessageBox::Ok);

          return;
        }
    }

  // At this point, whatever the way the modification was created, we
  // have it full and working. Use it to perform the modification
  // according to the user's requests.

  if(m_ui.leftEndCheckBox->checkState() == Qt::Checked)
    {
      polymer->setLeftEndModif(modif);
      mp_editorWnd->setWindowModified(true);
    }

  if(m_ui.rightEndCheckBox->checkState() == Qt::Checked)
    {
      polymer->setRightEndModif(modif);
      mp_editorWnd->setWindowModified(true);
    }

  updateModificationLineEdits();

  mp_editorWnd->updatePolymerEndsModifs();

  mp_editorWnd->updateWholeSequenceMasses(true);
  mp_editorWnd->updateSelectedSequenceMasses(true);

  return;
}


void
PolymerModificationDlg::unmodify()
{
  Polymer *polymer = mp_editorWnd->polymer();

  if(m_ui.leftEndCheckBox->checkState() == Qt::Checked)
    {
      polymer->setLeftEndModif();
      mp_editorWnd->setWindowModified(true);
    }

  if(m_ui.rightEndCheckBox->checkState() == Qt::Checked)
    {
      polymer->setRightEndModif();
      mp_editorWnd->setWindowModified(true);
    }

  updateModificationLineEdits();

  // Also update the labels of the buttons in the sequence editor
  // window.
  mp_editorWnd->updatePolymerEndsModifs();

  mp_editorWnd->updateWholeSequenceMasses(true);
  mp_editorWnd->updateSelectedSequenceMasses(true);
}

} // namespace msXpSmassXpert
