/**
 * \file output/ods/peptidesheet.cpp
 * \date 27/4/2017
 * \author Olivier Langella
 * \brief ODS spectra sheet
 */

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

#include "spectrasheet.h"
#include <tuple>
#include <pappsomspp/core/utils.h>
#include <pappsomspp/core/exception/exceptionnotfound.h>

SpectraSheet::SpectraSheet(OdsExport *p_ods_export,
                           CalcWriterInterface *p_writer,
                           const Project *p_project,
                           const QString &sheet_name,
                           bool displayIonMobilityInformations)
  : _p_project(p_project)
{
  m_displayIonMobilityInformations = displayIonMobilityInformations;
  _p_ods_export                    = p_ods_export;
  _p_writer                        = p_writer;
  p_writer->writeSheet(sheet_name);

  OdsTableSettings table_settings;
  table_settings.setVerticalSplit(1);
  _p_writer->setCurrentOdsTableSettings(table_settings);

  std::vector<IdentificationGroup *> identification_list =
    p_project->getIdentificationGroupList();
  for(IdentificationGroup *p_ident : identification_list)
    {
      // writeHeaders(p_ident);
      writeIdentificationGroup(p_ident);
    }
}

SpectraSheet::SpectraSheet(OdsExport *p_ods_export,
                           CalcWriterInterface *p_writer,
                           const Project *p_project,
                           bool displayIonMobilityInformations)
  : SpectraSheet(p_ods_export,
                 p_writer,
                 p_project,
                 QString("spectra"),
                 displayIonMobilityInformations)
{
  qDebug() << "m_displayIonMobilityInformations="
           << m_displayIonMobilityInformations;
}


void
SpectraSheet::writeCellHeader(PeptideListColumn column)
{
  qDebug() << (std::int8_t)column;
  _p_writer->setCellAnnotation(PeptideTableModel::getDescription(column));
  _p_writer->writeCell(PeptideTableModel::getTitle(column));
  qDebug();
}


void
SpectraSheet::writeHeaders(IdentificationGroup *p_ident)
{
  // Group ID	Peptide ID	Sample	Scan	Rt (minutes)	Sequence (top)	Modifs
  // (top)
  // Number of subgroups	Sub-groups Ids	Best E-value	Best hyperscore	m/z Obs
  // Charge	MH+ Obs	MH+ theo	DeltaMH+	Delta-ppm

  // MS Sample :	20120906_balliau_extract_1_A01_urnb-1
  const std::vector<MsRunSp> msrun_list = p_ident->getMsRunSpList();
  if(msrun_list.size() == 1)
    {
      _p_writer->writeCell("sample");
      _p_writer->writeLine();
      _p_writer->writeCell(msrun_list[0].get()->getSampleName());
      _p_writer->writeLine();
    }


  _p_writer->writeLine();
  _p_writer->writeCell("Group ID");
  _p_writer->writeCell("Peptide ID");

  writeCellHeader(PeptideListColumn::sample);
  writeCellHeader(PeptideListColumn::scan);
  writeCellHeader(PeptideListColumn::rt);
  if(m_displayIonMobilityInformations)
    {
      writeCellHeader(PeptideListColumn::ion_mobility_begin);
      writeCellHeader(PeptideListColumn::ion_mobility_end);
      writeCellHeader(PeptideListColumn::collision_energy);
    }

  writeCellHeader(PeptideListColumn::experimental_mz);
  _p_writer->setCellAnnotation("peptide sequence (best match)");
  _p_writer->writeCell("Sequence (top)");
  _p_writer->setCellAnnotation("peptide charge (best match)");
  _p_writer->writeCell("Charge (top)");
  _p_writer->setCellAnnotation("peptide modifications (best match)");
  _p_writer->writeCell("Modifs (top)");
  if(_p_project->getLabelingMethodSp().get() != nullptr)
    {
      _p_writer->setCellAnnotation("peptide label (best match)");
      _p_writer->writeCell("Label (top)");
    }
  _p_writer->writeCell("Best E-value");
  _p_writer->writeCell("Best hyperscore");
  writeCellHeader(PeptideListColumn::delta_mhplus);
  writeCellHeader(PeptideListColumn::delta_ppm);
}

void
SpectraSheet::writeBestPeptideEvidence(const GroupingGroup *p_group
                                       [[maybe_unused]],
                                       const PeptideEvidence *p_peptide_evidence
                                       [[maybe_unused]])
{

  pappso::QualifiedMassSpectrum mass_spectrum;
  if(m_displayIonMobilityInformations)
    {
      try
        {
          mass_spectrum = p_peptide_evidence->getQualifiedMassSpectrum(false);
        }
      catch(pappso::ExceptionNotFound &notfound)
        {
          // mz file not found, we can not get the qualified mass spectrum
          // return;
        }
    }

  _p_writer->writeLine();

  unsigned int group_number =
    p_peptide_evidence->getGrpPeptideSp().get()->getGroupNumber();
  unsigned int rank_number =
    p_peptide_evidence->getGrpPeptideSp().get()->getRank();

  _p_ods_export->setEvenOrOddStyle(group_number, _p_writer);
  _p_writer->writeCell(pappso::Utils::getLexicalOrderedString(group_number));
  _p_ods_export->setEvenOrOddStyle(rank_number, _p_writer);
  _p_writer->writeCell(
    p_peptide_evidence->getGrpPeptideSp().get()->getGroupingId());
  _p_writer->clearTableCellStyleRef();
  _p_writer->writeCell(p_peptide_evidence->getMsRunP()->getSampleName());
  _p_writer->writeCell((std::size_t)p_peptide_evidence->getScanNumber());
  _p_writer->writeCell(p_peptide_evidence->getRetentionTime());
  if(m_displayIonMobilityInformations)
    {
      _p_writer->writeCell(
        mass_spectrum
          .getParameterValue(
            //  pappso::QualifiedMassSpectrumParameter::IonMobOneOverK0Begin)
            pappso::QualifiedMassSpectrumParameter::IonMobOneOverK0Begin)
          .toDouble());
      _p_writer->writeCell(
        mass_spectrum
          .getParameterValue(
            // pappso::QualifiedMassSpectrumParameter::IonMobOneOverK0End)
            pappso::QualifiedMassSpectrumParameter::IonMobOneOverK0End)
          .toDouble());
      _p_writer->writeCell(
        mass_spectrum
          .getParameterValue(
            pappso::QualifiedMassSpectrumParameter::CollisionEnergy)
          .toDouble());
    }
  _p_writer->writeCell(p_peptide_evidence->getExperimentalMz());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getSequence());
  _p_writer->writeCell((std::size_t)p_peptide_evidence->getCharge());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getModifString());
  if(_p_project->getLabelingMethodSp().get() != nullptr)
    {
      const Label *p_label =
        p_peptide_evidence->getPeptideXtpSp().get()->getLabel();
      if(p_label != nullptr)
        {
          _p_writer->writeCell(p_label->getXmlId());
        }
      else
        {
          _p_writer->writeEmptyCell();
        }
    }
  _p_writer->writeCell(p_peptide_evidence->getEvalue());
  _p_writer->writeCell(
    p_peptide_evidence->getParam(PeptideEvidenceParam::tandem_hyperscore)
      .toDouble());
  _p_writer->writeCell(p_peptide_evidence->getDeltaMass());
  _p_writer->writeCell(p_peptide_evidence->getPpmDeltaMass());
}

void
SpectraSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{
  qDebug() << "m_displayIonMobilityInformations="
           << m_displayIonMobilityInformations;
  writeHeaders(p_ident);
  for(const std::pair<unsigned int, GroupingGroupSp> group_pair :
      p_ident->getGroupStore().getGroupMap())
    {

      std::vector<const PeptideEvidence *> peptide_evidence_list =
        group_pair.second.get()->getPeptideEvidenceList();

      std::sort(
        peptide_evidence_list.begin(),
        peptide_evidence_list.end(),
        [](const PeptideEvidence *a, const PeptideEvidence *b) {
          unsigned int arank = a->getGrpPeptideSp().get()->getRank();
          unsigned int ascan = a->getScanNumber();
          unsigned int brank = b->getGrpPeptideSp().get()->getRank();
          unsigned int bscan = b->getScanNumber();
          return std::tie(arank, a->getMsRunP()->getSampleName(), ascan) <
                 std::tie(brank, b->getMsRunP()->getSampleName(), bscan);
        });

      const PeptideEvidence *p_best_peptide_evidence = nullptr;

      for(auto &peptide_evidence : peptide_evidence_list)
        {
          if(p_best_peptide_evidence == nullptr)
            {
              p_best_peptide_evidence = peptide_evidence;
            }
          // change spectra :
          unsigned int arank =
            p_best_peptide_evidence->getGrpPeptideSp().get()->getRank();
          unsigned int ascan = p_best_peptide_evidence->getScanNumber();
          unsigned int brank =
            peptide_evidence->getGrpPeptideSp().get()->getRank();
          unsigned int bscan = peptide_evidence->getScanNumber();

          if(std::tie(arank,
                      p_best_peptide_evidence->getMsRunP()->getSampleName(),
                      ascan) !=
             std::tie(
               brank, peptide_evidence->getMsRunP()->getSampleName(), bscan))
            {
              // write p_best_peptide_match
              writeBestPeptideEvidence(group_pair.second.get(),
                                       p_best_peptide_evidence);
              p_best_peptide_evidence = peptide_evidence;
            }
          else
            {
              if(p_best_peptide_evidence->getEvalue() >
                 peptide_evidence->getEvalue())
                {
                  p_best_peptide_evidence = peptide_evidence;
                }
            }
        }

      if(p_best_peptide_evidence != nullptr)
        {
          writeBestPeptideEvidence(group_pair.second.get(),
                                   p_best_peptide_evidence);
        }
    }
  _p_writer->writeLine();
  _p_writer->writeLine();
}
