/* 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>
#include <libXpertMass/PolChemDefEntity.hpp>

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


namespace MsXpS
{

namespace massxpert
{

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


  PolymerModificationDlg::~PolymerModificationDlg()
  {
  }


  bool
  PolymerModificationDlg::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));

    populateModificationList();

    if(mp_editorWnd)
      updateModificationLineEdits();


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

    if(m_polymerEnd & libXpertMass::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()
  {
    libXpertMass::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()
  {
    libXpertMass::PolChemDefCstSPtr polChemDefCstSPtr =
      mp_editorWnd->polChemDefRendering()->getPolChemDef();
    Q_ASSERT(polChemDefCstSPtr);

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

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

    return true;
  }


  bool
  PolymerModificationDlg::parseModifDefinition(libXpertMass::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()
  {
    libXpertMass::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.

    libXpertMass::Modif modif(polymer->getPolChemDefCstSPtr(), "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(libXpertMass::Modif::isNameInList(
             text, polymer->getPolChemDefCstSPtr()->modifList(), &modif) == -1)
          {
            QMessageBox::warning(
              this,
              tr("massXpert - libXpertMass::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()
  {
    libXpertMass::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 massxpert

} // namespace MsXpS
