/**
 * \file output/ods/peptidesheetall.cpp
 * \date 13/01/2020
 * \author Olivier Langella
 * \brief ODS spectra sheet with all PSM
 */

/*******************************************************************************
 * Copyright (c) 2020 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/>.
 *
 ******************************************************************************/

#include "spectrasheetall.h"
#include <tuple>
#include <pappsomspp/utils.h>

SpectraSheetAll::SpectraSheetAll(OdsExport *p_ods_export,
                                 CalcWriterInterface *p_writer,
                                 const Project *p_project,
                                 const QString &sheet_name)
  : _p_project(p_project)
{
  _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);
    }
}

SpectraSheetAll::SpectraSheetAll(OdsExport *p_ods_export,
                                 CalcWriterInterface *p_writer,
                                 const Project *p_project)
  : SpectraSheetAll(p_ods_export, p_writer, p_project, QString("PSMs"))
{
}


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


void
SpectraSheetAll::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);
  writeCellHeader(PeptideListColumn::experimental_mz);
  _p_writer->setCellAnnotation("peptide sequence");
  _p_writer->writeCell("Sequence");
  _p_writer->setCellAnnotation("peptide charge");
  _p_writer->writeCell("Charge");
  _p_writer->setCellAnnotation("peptide modifications");
  _p_writer->writeCell("Modifs");
  if(_p_project->getLabelingMethodSp().get() != nullptr)
    {
      _p_writer->setCellAnnotation("peptide label");
      _p_writer->writeCell("Label");
    }
  _p_writer->writeCell("E-value");
  _p_writer->writeCell("hyperscore");
  writeCellHeader(PeptideListColumn::delta_mhplus);
  writeCellHeader(PeptideListColumn::delta_ppm);
}

void
SpectraSheetAll::writePeptideEvidence(const GroupingGroup *p_group
                                      [[maybe_unused]],
                                      const PeptideEvidence *p_peptide_evidence
                                      [[maybe_unused]])
{

  _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());
  _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
SpectraSheetAll::writeIdentificationGroup(IdentificationGroup *p_ident)
{

  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);
        });

      auto last =
        std::unique(peptide_evidence_list.begin(), peptide_evidence_list.end());
      peptide_evidence_list.erase(last, peptide_evidence_list.end());

      for(auto &peptide_evidence : peptide_evidence_list)
        {

          // write p_best_peptide_match
          writePeptideEvidence(group_pair.second.get(), peptide_evidence);
        }
    }
  _p_writer->writeLine();
  _p_writer->writeLine();
}
