/**
 * \file /output/ods/ptm/ptmspectrasheet.cpp
 * \date 16/2/2018
 * \author Olivier Langella
 * \brief ODS PTM spectra sheet
 */

/*******************************************************************************
 * Copyright (c) 2018 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 "ptmspectrasheet.h"
#include <tuple>
#include <pappsomspp/core/utils.h>

PtmSpectraSheet::PtmSpectraSheet(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);
    }
}

PtmSpectraSheet::PtmSpectraSheet(OdsExport *p_ods_export,
                                 CalcWriterInterface *p_writer,
                                 const Project *p_project)
  : PtmSpectraSheet(p_ods_export, p_writer, p_project, QString("PTM spectra"))
{
}


void
PtmSpectraSheet::writeCellHeader(PeptideListColumn column)
{
  qDebug();
  _p_writer->setCellAnnotation(PeptideTableModel::getDescription(column));
  _p_writer->writeCell(PeptideTableModel::getTitle(column));
  qDebug();
}


void
PtmSpectraSheet::writeHeaders(IdentificationGroup *p_ident)
{
  // Group ID	Sub-group ID	Phosphopeptide ID	Sample	Scan	Rt	Sequence (top)
  // Modifs (top)	Best position in peptide	All observed positions in
  // phosphopeptide	Number of phosphoislands	Phosphoislands Ids	Best e-value
  // 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();

  // Group ID
  _p_writer->writeCell("group ID");

  // Sub-group ID

  // Phosphopeptide ID
  writeCellHeader(PeptideListColumn::peptide_grouping_id);

  // Modifs (top)	Best position in peptide	All observed positions in
  // phosphopeptide	Number of phosphoislands	Phosphoislands Ids	Best e-value
  // Charge	MH+ Obs	MH+ theo	DeltaMH+	Delta-ppm

  // Sample
  writeCellHeader(PeptideListColumn::sample);

  // Scan
  writeCellHeader(PeptideListColumn::scan);

  // Rt
  writeCellHeader(PeptideListColumn::rt);

  writeCellHeader(PeptideListColumn::charge);

  writeCellHeader(PeptideListColumn::experimental_mz);

  // Sequence (top)
  _p_writer->setCellAnnotation("peptide sequence (best match)");
  _p_writer->writeCell("sequence (top)");


  // Modifs (top)
  _p_writer->setCellAnnotation("peptide modification list (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)");
    }

  // Best position in peptide
  _p_writer->setCellAnnotation("best PTM positions for this sample/scan");
  _p_writer->writeCell("best positions in peptide");

  // All observed positions in phosphopeptide
  _p_writer->setCellAnnotation("All observed positions for this sample/scan");
  _p_writer->writeCell("all positions in peptide");

  // Number of phosphoislands
  _p_writer->setCellAnnotation(
    "Number of phosphoislands share this sample/scan");
  _p_writer->writeCell("number of phosphoislands");

  // Phosphoislands Ids
  _p_writer->setCellAnnotation("Phosphoislands id list");
  _p_writer->writeCell("phosphoislands");

  // Best e-value
  _p_writer->writeCell("best E-value");


  _p_writer->writeCell("best hyperscore");

  // MH+ Obs
  writeCellHeader(PeptideListColumn::experimental_mhplus);

  // MH+ theo
  writeCellHeader(PeptideListColumn::theoretical_mhplus);

  // DeltaMH+
  writeCellHeader(PeptideListColumn::delta_mhplus);

  // Delta-ppm
  writeCellHeader(PeptideListColumn::delta_ppm);
}

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

  _p_writer->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();

  _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((std::size_t)p_peptide_evidence->getCharge());
  _p_writer->writeCell(p_peptide_evidence->getExperimentalMz());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getSequence());
  _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();
        }
    }
  QStringList position_list;
  for(unsigned int position :
      ptm_sample_scan.getBestPtmPositionList(_p_ptm_grouping_experiment))
    {
      position_list << QString("%1").arg(position + 1);
    }
  _p_writer->writeCell(position_list.join(" "));

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

  _p_writer->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();
        }
    }
  _p_writer->writeCell(position_list.join(" "));

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

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

void
PtmSpectraSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{
  qDebug();
  _p_ptm_grouping_experiment = p_ident->getPtmGroupingExperiment();

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

  _p_writer->writeLine();
  _p_writer->writeLine();
  qDebug();
}

void
PtmSpectraSheet::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);
    }
  qDebug();
}
