
/*******************************************************************************
 * Copyright (c) 2017 Olivier Langella <olivier.langella@u-psud.fr>.
 *
 * This file is part of XTPcpp.
 *
 *     XTPcpp 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.
 *
 *     XTPcpp 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 XTPcpp.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "peptidewindow.h"
#include "../project_view/projectwindow.h"
#include "../../config.h"
#include "ui_peptide_detail_view.h"
#include <pappsomspp/exception/exceptionnotfound.h>
#include <pappsomspp/massspectrum/qualifiedmassspectrum.h>
#include <QFileDialog>
#include <QSettings>
#include <QDebug>
#include <QProcess>
#include <QSvgGenerator>
#include <QMessageBox>
#include <QSpacerItem>


void
SpectrumSpLoaderThread::doLoadSpectrumSp(PeptideEvidence *p_peptide_evidence)
{
  qDebug() << "begin";
  pappso::MassSpectrumCstSPtr spectrum;
  try
    {
      spectrum =
        p_peptide_evidence->getIdentificationDataSource()
          ->getMassSpectrumCstSPtr(p_peptide_evidence->getScanNumber());


      emit spectrumSpReady(spectrum, QString(""), QString(""));
    }

  catch(pappso::ExceptionNotFound &error)
    {
      qDebug() << "SpectrumSpLoaderThread::doLoadSpectrumSp error "
               << error.qwhat();
      emit spectrumSpReady(spectrum, error.qwhat(), QString(""));
    }

  catch(pappso::PappsoException &error)
    {
      qDebug() << "SpectrumSpLoaderThread::doLoadSpectrumSp error "
               << error.qwhat();
      emit spectrumSpReady(spectrum, QString(""), error.qwhat());
    }

  catch(std::exception &error)
    {
      qDebug() << "SpectrumSpLoaderThread::doLoadSpectrumSp error "
               << error.what();
      emit spectrumSpReady(spectrum, QString(""), QString(error.what()));
    }
  qDebug() << "SpectrumSpLoaderThread::doLoadSpectrumSp end";
}

PeptideWindow::PeptideWindow(ProjectWindow *parent)
  : QMainWindow(parent), ui(new Ui::PeptideDetailView)
{
  qDebug() << "PeptideWindow::PeptideWindow begin";
  _p_project_window = parent;
  ui->setupUi(this);
  /*
   */
  SpectrumSpLoaderThread *worker = new SpectrumSpLoaderThread;
  worker->moveToThread(&_spectrum_loader_thread);
  _spectrum_loader_thread.start();


  if(_p_project_window->getProjectP() != nullptr)
    {
      setWindowTitle(
        QString("%1 - Peptide details")
          .arg(_p_project_window->getProjectP()->getProjectName()));
    }

  QSettings settings;
  QString precision_str =
    settings.value("peptideview/precision", "0.2 dalton").toString();

  _p_precision = pappso::PrecisionFactory::fromString(precision_str);

  ui->file_not_found->setVisible(false);

  mp_movie = new QMovie(":icons/resources/icons/icon_wait.gif");
  mp_movie->start();
  mp_movie->setScaledSize(QSize(20, 20));

  _mz_label = new QLabel("");
  _mz_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  _mz_label->setMovie(mp_movie);
  ui->statusbar->addWidget(_mz_label);
  mp_status_label = new QLabel("");
  ui->statusbar->addWidget(mp_status_label);
  QWidget *p_spacer = new QWidget();
  p_spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  ui->statusbar->addWidget(p_spacer);
  _peak_label = new QLabel("");
  _peak_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  ui->statusbar->addWidget(_peak_label);
  ui->statusbar->addWidget(p_spacer);
  _ion_label = new QLabel("");
  _ion_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  ui->statusbar->addWidget(_ion_label);

  ui->spectrum_widget->setMaximumIsotopeNumber(3);
  ui->spectrum_widget->setMaximumIsotopeRank(6);

#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(_p_project_window,
          &ProjectWindow::identificationGroupGrouped,
          this,
          &PeptideWindow::doIdentificationGroupGrouped);

  connect(this,
          &PeptideWindow::loadSpectrumSp,
          worker,
          &SpectrumSpLoaderThread::doLoadSpectrumSp);
  connect(worker,
          &SpectrumSpLoaderThread::spectrumSpReady,
          this,
          &PeptideWindow::doSpectrumSpReady);
  connect(_p_project_window,
          &ProjectWindow::projectNameChanged,
          this,
          &PeptideWindow::doProjectNameChanged);

  /*
  connect(ui->spectrum_widget,
          &pappso::SpectrumWidget::mzChanged,
          this,
          &PeptideWindow::setMz);
  connect(ui->spectrum_widget,
          qOverload<const pappso::Peak *>(&pappso::SpectrumWidget::peakChanged),
          this,
          &PeptideWindow::setPeak);
  connect(
    ui->spectrum_widget,
    qOverload<pappso::PeakIonIsotopeMatch>(&pappso::SpectrumWidget::ionChanged),
    this,
    &PeptideWindow::setIon);

          */
#else
  // Qt4 code
  connect(_p_project_window,
          SIGNAL(identificationGroupGrouped(IdentificationGroup *)),
          this,
          SLOT(doIdentificationGroupGrouped(IdentificationGroup *)));

  connect(this,
          SIGNAL(loadSpectrumSp(PeptideMatch *)),
          worker,
          SLOT(doLoadSpectrumSp(PeptideMatch *)));
  connect(worker,
          SIGNAL(spectrumSpReady(pappso::SpectrumSp, QString, QString)),
          this,
          SLOT(doSpectrumSpReady(pappso::SpectrumSp, QString, QString)));
  connect(
    _p_spectrum_overlay, SIGNAL(mzChanged(double)), this, SLOT(setMz(double)));
  // connect(_protein_table_model_p, SIGNAL(layoutChanged()), this,
  // SLOT(updateStatusBar()));
#endif

  qDebug() << "PeptideWindow::PeptideWindow end";
}

PeptideWindow::~PeptideWindow()
{

  _spectrum_loader_thread.quit();
  _spectrum_loader_thread.wait();
  delete ui;
}


void
PeptideWindow::setIon(pappso::PeakIonIsotopeMatchCstSPtr ion)
{
  if(ion == nullptr)
    {
      _ion_label->setText("");
    }
  else
    {
      QString plusstr = "+";
      plusstr         = plusstr.repeated(ion->getCharge());
      _ion_label->setText(
        QString("%1%2%3 (+%4) - th. isotope ratio %5%")
          .arg(ion->getPeptideFragmentIonSp().get()->getPeptideIonName())
          .arg(ion->getPeptideFragmentIonSp().get()->size())
          .arg(plusstr)
          .arg(
            ion->getPeptideNaturalIsotopeAverageSp().get()->getIsotopeNumber())
          .arg((int)(ion->getPeptideNaturalIsotopeAverageSp()
                       .get()
                       ->getIntensityRatio() *
                     100)));
    }
}

void
PeptideWindow::setPeak(pappso::DataPointCstSPtr p_peak_match)
{
  qDebug() << "PeptideWindow::setPeak begin";
  if(p_peak_match == nullptr)
    {
      _peak_label->setText(QString("no peak"));
      _ion_label->setText("");
    }
  else
    {
      _peak_label->setText(QString("peak mz=%1 intensity=%2")
                             .arg(QString::number(p_peak_match->x, 'g', 10))
                             .arg(p_peak_match->y));
    }
}

void
PeptideWindow::setMz(double mz)
{
  if(mz > 0)
    {
      _mz_label->setText(QString("mz=%1").arg(QString::number(mz, 'g', 10)));
    }
  else
    {
      _mz_label->setText("");
    }
}

void
PeptideWindow::doIdentificationGroupGrouped(
  IdentificationGroup *p_identification_group [[maybe_unused]])
{
  updateDisplay();
}

void
PeptideWindow::updateDisplay()
{
  try
    {
      ui->sequence_label->setText(
        _p_peptide_evidence->getPeptideXtpSp().get()->toString());
      ui->mz_label->setText(
        QString("%1").arg(_p_peptide_evidence->getPeptideXtpSp().get()->getMz(
          _p_peptide_evidence->getCharge())));
      ui->z_label->setText(QString("%1").arg(_p_peptide_evidence->getCharge()));
      ui->scan_label->setText(
        QString("%1").arg(_p_peptide_evidence->getScanNumber()));
      ui->sample_label->setText(
        _p_peptide_evidence->getMsRunP()->getSampleName());
      ui->modification_label->setText(
        _p_peptide_evidence->getPeptideXtpSp().get()->getModifString());
      ui->hyperscore_label->setText(
        _p_peptide_evidence->getParam(PeptideEvidenceParam::tandem_hyperscore)
          .toString());
      ui->evalue_label->setText(
        QString::number(_p_peptide_evidence->getEvalue(), 'g', 4));
      ui->mh_label->setText(QString::number(
        _p_peptide_evidence->getPeptideXtpSp().get()->getMz(1), 'f', 4));
      ui->mz_label->setText(
        QString::number(_p_peptide_evidence->getPeptideXtpSp().get()->getMz(
                          _p_peptide_evidence->getCharge()),
                        'f',
                        4));
      ui->expmz_label->setText(
        QString::number(_p_peptide_evidence->getExperimentalMz(), 'f', 4));
      ui->delta_label->setText(
        QString::number(_p_peptide_evidence->getDeltaMass(), 'g', 4));
      ui->retention_time_label->setText(
        QString::number(_p_peptide_evidence->getRetentionTime(), 'f', 2));
      ui->retention_time_min_label->setText(
        QString::number(_p_peptide_evidence->getRetentionTime() / 60, 'f', 2));
    }
  catch(pappso::PappsoException &exception_pappso)
    {
      QMessageBox::warning(this,
                           tr("Unable to display peptide details :"),
                           exception_pappso.qwhat());
    }
  catch(std::exception &exception_std)
    {
      QMessageBox::warning(
        this, tr("Unable to display peptide details :"), exception_std.what());
    }
}


void
PeptideWindow::chooseDefaultMzDataDir()
{
  QSettings settings;
  QString default_location = settings.value("path/mzdatadir", "").toString();

  QString filename =
    QFileDialog::getExistingDirectory(this,
                                      tr("Choose default mz data directory"),
                                      default_location,
                                      QFileDialog::ShowDirsOnly);

  if(filename.isEmpty())
    {
      return;
    }
  QString path = QFileInfo(filename).absoluteFilePath();
  settings.setValue("path/mzdatadir", path);
  ui->mz_data_dir_label->setText(path);


  qDebug() << "PeptideWindow::chooseDefaultMzDataDir begin";
  ui->file_not_found->setVisible(false);
  ui->xic_button->setEnabled(true);
  ui->spectrum_widget->setVisible(true);
  emit loadSpectrumSp(_p_peptide_evidence);
  mp_status_label->setText("loading spectrum");
}

void
PeptideWindow::openInPeptideViewer()
{
  QSettings settings;
  QString program =
    settings.value("application/peptideviewer", "/usr/bin/pt-peptideviewer")
      .toString();
  QStringList arguments;
  arguments << _p_peptide_evidence->getPeptideXtpSp().get()->toString()
            << QString("%1").arg(_p_peptide_evidence->getCharge())
            << _p_peptide_evidence->getMsRunP()->getFileName()
            << QString("%1").arg(_p_peptide_evidence->getScanNumber());

  qDebug() << "PeptideWindow::openInPeptideViewer " << program << " "
           << arguments.join(" ");
  QProcess *myProcess = new QProcess(this);
  myProcess->start(program, arguments);
}


void
PeptideWindow::openInXicViewer()
{
  _p_project_window->openInXicViewer(_p_peptide_evidence);
}

void
PeptideWindow::doSpectrumSpReady(pappso::MassSpectrumCstSPtr spectrum_sp,
                                 QString error,
                                 QString fatal_error)
{
  qDebug() << "PeptideWindow::doSpectrumSpReady begin error=" << error
           << " fatal_error=" << fatal_error;
  mp_status_label->clear();
  _mz_label->clear();
  if((error.isEmpty()) && (fatal_error.isEmpty()))
    {
      ui->file_not_found->setVisible(false);
      ui->spectrum_widget->setVisible(true);
      ui->xic_button->setEnabled(true);

      ui->spectrum_widget->setMsLevel(2);
      ui->spectrum_widget->setMassSpectrumCstSPtr(spectrum_sp);
      qDebug() << "PeptideWindow::doSpectrumSpReady plot";
      ui->spectrum_widget->plot();
      qDebug() << "PeptideWindow::doSpectrumSpReady rescale";
      ui->spectrum_widget->rescale();
      _spectrum_is_ready = true;
    }
  if(!error.isEmpty())
    {
      // not found
      mp_status_label->setText(tr("spectrum not found"));
      QSettings settings;
      QString path = settings.value("path/mzdatadir", "").toString();

      ui->mz_data_dir_label->setText(path);

      ui->file_not_found->setVisible(true);
      ui->spectrum_widget->setVisible(false);
      ui->xic_button->setEnabled(false);
      _spectrum_is_ready = false;
    }
  if(!fatal_error.isEmpty())
    {
      // fatal_error

      QMessageBox::warning(
        this,
        tr("Oops! an error occurred in XTPCPP. Don't panic :"),
        fatal_error);
      mp_status_label->setText(tr("ERROR reading spectrum"));
      QSettings settings;
      QString path = settings.value("path/mzdatadir", "").toString();

      ui->mz_data_dir_label->setText(path);

      ui->file_not_found->setVisible(true);
      ui->spectrum_widget->setVisible(false);
      _spectrum_is_ready = false;
    }
  qDebug() << "PeptideWindow::doSpectrumSpReady end";
}

void
PeptideWindow::setPeptideEvidence(PeptideEvidence *p_peptide_evidence)
{
  qDebug() << "PeptideWindow::setPeptideEvidence begin " << p_peptide_evidence;
  _p_peptide_evidence = p_peptide_evidence;
  _spectrum_is_ready  = false;

  qDebug() << "PeptideWindow::setPeptideEvidence 1";

  ui->file_not_found->setVisible(false);
  ui->spectrum_widget->setVisible(true);
  mp_status_label->setText("loading spectrum");

  qDebug() << "PeptideWindow::setPeptideEvidence 2";
  pappso::PeptideSp peptide = _p_peptide_evidence->getPeptideXtpSp();
  qDebug() << "PeptideWindow::setPeptideEvidence 3";
  ui->spectrum_widget->setMs2Precision(_p_precision);
  ui->spectrum_widget->setPeptideCharge(_p_peptide_evidence->getCharge());
  ui->spectrum_widget->setPeptideSp(peptide);

  qDebug() << "PeptideWindow::setPeptideEvidence 4";
  // ui->spectrum_widget->plot();

  updateDisplay();
  qDebug() << "PeptideWindow::setPeptideEvidence emit "
              "loadSpectrumSp(_p_peptide_match)";
  emit loadSpectrumSp(_p_peptide_evidence);
  qDebug() << "PeptideWindow::setPeptideEvidence end";
}

void
PeptideWindow::doMsmsPrecisionChanged(pappso::PrecisionPtr precision)
{

  qDebug() << "PeptideWindow::doMsmsPrecisionChanged begin "
           << precision->toString();
  QSettings settings;
  _p_precision = precision;
  ui->spectrum_widget->setMs2Precision(_p_precision);
  qDebug() << "PeptideWindow::doMsmsPrecisionUnitChanged plot ";
  ui->spectrum_widget->plot();

  settings.setValue("peptideview/precision", precision->toString());

  qDebug() << "PeptideWindow::doMsmsPrecisionUnitChanged end ";
}

void
PeptideWindow::doSaveSvg()
{

  try
    {
      QSettings settings;
      QString default_location =
        settings.value("path/export_svg", "").toString();

      QString proposed_filename =
        QString("%1/%2_%3.svg")
          .arg(default_location)
          .arg(_p_peptide_evidence->getMsRunP()->getSampleName())
          .arg(_p_peptide_evidence->getScanNumber());

      if(_p_peptide_evidence->getValidationState() == ValidationState::grouped)
        {
          proposed_filename =
            QString("%1/%2_%3_%4.svg")
              .arg(default_location)
              .arg(
                _p_peptide_evidence->getGrpPeptideSp().get()->getGroupingId())
              .arg(_p_peptide_evidence->getMsRunP()->getSampleName())
              .arg(_p_peptide_evidence->getScanNumber());
        }

      QString filename =
        QFileDialog::getSaveFileName(this,
                                     tr("Save SVG file"),
                                     proposed_filename,
                                     tr("Scalable Vector Graphic (*.svg)"));

      if(filename.isEmpty())
        {
          return;
        }

      settings.setValue("path/export_svg", QFileInfo(filename).absolutePath());


      ui->spectrum_widget->toSvgFile(
        filename,
        tr("%1 SVG spectrum generator").arg(SOFTWARE_NAME),
        tr("This is an annotated SVG spectrum"),
        QSize(1200, 500));
      // emit operateXpipFile(filename);
    }
  catch(pappso::PappsoException &error)
    {
      QMessageBox::warning(
        this, tr("Error trying to save spectrum to SVG file :"), error.qwhat());
    }
}

void
PeptideWindow::doProjectNameChanged(QString name)
{
  setWindowTitle(tr("%1 - Peptide details").arg(name));
}
