/**
 * \file output/ods/ptm/comparptmspectrasheet.h
 * \date 17/10/2024
 * \author Olivier Langella
 * \brief ods output to compare phospho ptm spectra
 */

/*******************************************************************************
 * Copyright (c) 2024 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.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/>.
 *
 ******************************************************************************/

#include "comparptmspectrasheet.h"
#include <pappsomspp/core/exception/exceptioninterrupted.h>
#include <pappsomspp/core/utils.h>


ComparPtmSpectraSheet::ComparPtmSpectraSheet(OdsExport *p_ods_export,
                                             CalcWriterInterface *p_writer,
                                             const Project *p_project,
                                             SubMonitor &sub_monitor)
  : mp_project(p_project), m_subMonitor(sub_monitor)
{
  mp_odsExport           = p_ods_export;
  mp_calcWriterInterface = p_writer;
  m_titleSheet           = "PTM compar spectra";


  msp_labelingMethod = p_project->getLabelingMethodSp();

  if(msp_labelingMethod.get() != nullptr)
    {
      m_labelPtrList = msp_labelingMethod.get()->getLabelList();
    }
    
}

ComparPtmSpectraSheet::~ComparPtmSpectraSheet()
{
}

void
ComparPtmSpectraSheet::writeSheet()
{
  mp_calcWriterInterface->writeSheet(m_titleSheet);

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

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

void
ComparPtmSpectraSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{

  qDebug() << " begin";
  mp_currentIdentificationGroup = p_ident;
  writeHeaders(p_ident);


  mp_currentPtmGroupingExperiment = p_ident->getPtmGroupingExperiment();

  writeHeaders(p_ident);
  for(const PtmIslandSubgroupSp &ptm_island_subgroup_sp :
      mp_currentPtmGroupingExperiment->getPtmIslandSubgroupList())
    {
      writePtmIslandSubgroupSp(ptm_island_subgroup_sp);
    }

  mp_calcWriterInterface->writeLine();
  mp_calcWriterInterface->writeLine();
  qDebug() << " end";
}


void
ComparPtmSpectraSheet::writeHeaders(IdentificationGroup *p_ident)
{
  // Group ID, Sub-group ID, Top PhosphoIsland ID, Top PhosphoIsland protein,
  // Positions, Number of proteins, 20141125_mauriat_triplex-T10F01

  qDebug();

  // MS Sample :	20120906_balliau_extract_1_A01_urnb-1
  m_currentMsRunSpList = p_ident->getMsRunSpList();
  if(m_currentMsRunSpList.size() == 1)
    {
      mp_calcWriterInterface->writeCell("sample");
      mp_calcWriterInterface->writeLine();
      mp_calcWriterInterface->writeCell(
        m_currentMsRunSpList[0].get()->getSampleName());
      mp_calcWriterInterface->writeLine();
    }

  std::sort(m_currentMsRunSpList.begin(),
            m_currentMsRunSpList.end(),
            [](MsRunSp &a, MsRunSp &b) {
              return a.get()->getXmlId() < b.get()->getXmlId();
            });

  qDebug();

  //_p_writer->writeLine();
  mp_calcWriterInterface->writeCell("Group ID");
  mp_calcWriterInterface->writeCell("Subgroup ID");
  //_p_writer->setCellAnnotation("MS sample name (MS run)");
  mp_calcWriterInterface->writeCell("Top PhosphoIsland ID");
  mp_calcWriterInterface->writeCell("Top PhosphoIsland protein");
  mp_calcWriterInterface->writeCell("Positions");
  mp_calcWriterInterface->writeCell("Number of proteins");

  qDebug();

  std::size_t total = m_currentMsRunSpList.size();
  std::size_t i     = 0;
  for(MsRunSp &msrun_sp : m_currentMsRunSpList)
    {
      m_subMonitor.setStatus(
        QObject::tr("writing %1 MSrun informations (%2 on %3)")
          .arg(msrun_sp.get()->getRunId())
          .arg(i + 1)
          .arg(total));
      qDebug();
      if(m_subMonitor.shouldIstop())
        {
          throw pappso::ExceptionInterrupted(
            QObject::tr("ODS PTM compar sheet writing interrupted"));
        }
      qDebug();
      if(msp_labelingMethod == nullptr)
        {
          mp_calcWriterInterface->writeCell(msrun_sp.get()->getSampleName());
        }
      else
        {
          for(const Label *p_label : m_labelPtrList)
            {
              mp_calcWriterInterface->writeCell(
                QString("%1-%2")
                  .arg(msrun_sp.get()->getSampleName())
                  .arg(p_label->getXmlId()));
            }
        }
      i++;
    }
  qDebug();
}

void
ComparPtmSpectraSheet::writePtmIslandSubgroupSp(
  const PtmIslandSubgroupSp &ptm_island_subgroup_sp)
{
  qDebug();
  struct PtmSampleScanOccurence
  {
    PtmSampleScan ptm_sample_scan;
    std::set<const PtmIsland *> ptmisland_occurence_list;
  };
  std::vector<PtmSampleScanOccurence> ptm_sample_scan_occurence_list;

  for(PtmIslandSp ptm_island_sp :
      ptm_island_subgroup_sp.get()->getPtmIslandList())
    {
      if(ptm_island_sp->isChecked())
        {
          qDebug();
          for(PeptideMatch peptide_match :
              ptm_island_sp.get()->getPeptideMatchList())
            {

              qDebug();
              std::vector<PtmSampleScanOccurence>::iterator it_ptm =
                ptm_sample_scan_occurence_list.begin();
              std::vector<PtmSampleScanOccurence>::iterator it_ptm_end =
                ptm_sample_scan_occurence_list.end();
              while((it_ptm != it_ptm_end) &&
                    (it_ptm->ptm_sample_scan.add(peptide_match) == false))
                {
                  // peptide added
                  it_ptm++;
                }
              if(it_ptm == it_ptm_end)
                {
                  qDebug();
                  // peptide NOT added
                  PtmSampleScanOccurence new_occurence = {
                    PtmSampleScan(peptide_match),
                    std::set<const PtmIsland *>()};
                  new_occurence.ptmisland_occurence_list.insert(
                    ptm_island_sp.get());
                  ptm_sample_scan_occurence_list.push_back(new_occurence);
                  qDebug();
                }
              else
                {
                  // peptide added
                  qDebug();
                  it_ptm->ptmisland_occurence_list.insert(ptm_island_sp.get());

                  qDebug();
                }
            }
        }
    }

  qDebug();

  for(PtmSampleScanOccurence &occurence : ptm_sample_scan_occurence_list)
    {
      writeBestPeptideEvidence(occurence.ptm_sample_scan,
                               occurence.ptmisland_occurence_list);
    }
}

void
ComparPtmSpectraSheet::writeBestPeptideEvidence(
  const PtmSampleScan &ptm_sample_scan,
  std::set<const PtmIsland *> &ptmisland_occurence_list)
{

  mp_calcWriterInterface->writeLine();

  const PeptideEvidence *p_peptide_evidence =
    ptm_sample_scan.getRepresentativePeptideMatch().getPeptideEvidence();

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

  mp_odsExport->setEvenOrOddStyle(group_number, mp_calcWriterInterface);
  mp_calcWriterInterface->writeCell(
    pappso::Utils::getLexicalOrderedString(group_number));
  mp_odsExport->setEvenOrOddStyle(rank_number, mp_calcWriterInterface);
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getGrpPeptideSp().get()->getGroupingId());
  mp_calcWriterInterface->clearTableCellStyleRef();
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getMsRunP()->getSampleName());
  mp_calcWriterInterface->writeCell(
    (std::size_t)p_peptide_evidence->getScanNumber());
  mp_calcWriterInterface->writeCell(p_peptide_evidence->getRetentionTime());
  mp_calcWriterInterface->writeCell(
    (std::size_t)p_peptide_evidence->getCharge());
  mp_calcWriterInterface->writeCell(p_peptide_evidence->getExperimentalMz());
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getSequence());
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getModifString());
  if(msp_labelingMethod.get() != nullptr)
    {
      const Label *p_label =
        p_peptide_evidence->getPeptideXtpSp().get()->getLabel();
      if(p_label != nullptr)
        {
          mp_calcWriterInterface->writeCell(p_label->getXmlId());
        }
      else
        {
          mp_calcWriterInterface->writeEmptyCell();
        }
    }
  QStringList position_list;
  for(unsigned int position :
      ptm_sample_scan.getBestPtmPositionList(mp_currentPtmGroupingExperiment))
    {
      position_list << QString("%1").arg(position + 1);
    }
  mp_calcWriterInterface->writeCell(position_list.join(" "));

  position_list.clear();
  // return _ptm_sample_scan_list.at(row).get()->getObservedPtmPositionList();
  for(unsigned int position : ptm_sample_scan.getObservedPtmPositionList(
        mp_currentPtmGroupingExperiment))
    {
      position_list << QString("%1").arg(position + 1);
    }
  mp_calcWriterInterface->writeCell(position_list.join(" "));

  mp_calcWriterInterface->writeCell(ptmisland_occurence_list.size());
  position_list.clear();
  // return _ptm_sample_scan_list.at(row).get()->getObservedPtmPositionList();
  for(const PtmIsland *ptm_island : ptmisland_occurence_list)
    {
      if(ptm_island->isChecked())
        {
          position_list << ptm_island->getGroupingId();
        }
    }
  mp_calcWriterInterface->writeCell(position_list.join(" "));

  mp_calcWriterInterface->writeCell(p_peptide_evidence->getEvalue());
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getParam(PeptideEvidenceParam::tandem_hyperscore)
      .toDouble());

  mp_calcWriterInterface->writeCell(p_peptide_evidence->getExperimentalMass() +
                                    pappso::MHPLUS);
  mp_calcWriterInterface->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getMz(1));
  mp_calcWriterInterface->writeCell(p_peptide_evidence->getDeltaMass());
  mp_calcWriterInterface->writeCell(p_peptide_evidence->getPpmDeltaMass());
}
