/**
 * \file output/ods/comparspectrabypeptide.cpp
 * \date 11/01/2018
 * \author Olivier Langella
 * \brief usefull for peptidomic
 */

/*******************************************************************************
 * Copyright (c) 2018 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 "comparspectrabypeptide.h"
#include <pappsomspp/utils.h>
#include "../../config.h"
#include <QDebug>
#include <QSettings>


ComparSpectraByPeptide::ComparSpectraByPeptide(OdsExport *p_ods_export,
                                               CalcWriterInterface *p_writer,
                                               const Project *p_project)
  : _p_project(p_project)
{
  _p_ods_export        = p_ods_export;
  _p_writer            = p_writer;
  _sp_labelling_method = p_project->getLabelingMethodSp();

  if(_sp_labelling_method.get() != nullptr)
    {
      _label_list = _sp_labelling_method.get()->getLabelList();
    }
}

void
ComparSpectraByPeptide::writeSheet()
{
  _p_writer->writeSheet("peptidomic compar spectra");

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

void
ComparSpectraByPeptide::writeHeaders(IdentificationGroup *p_ident)
{


  // MS Sample :	20120906_balliau_extract_1_A01_urnb-1
  _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();
    }

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


  _p_writer->writeCell("Group ID");
  _p_writer->writeCell("Peptide ID");
  _p_writer->setCellAnnotation(
    "peptide sequence where all leucine are turned into isoleucine");
  _p_writer->writeCell("SequenceLI");
  _p_writer->writeCell("Modifs");
  _p_writer->setCellAnnotation(
    "the charge associated to the best peptide Evalue for this sequenceLI");
  _p_writer->writeCell("Charge");
  _p_writer->setCellAnnotation("theoretical mh");
  _p_writer->writeCell("MH+ theo");
  _p_writer->writeCell("Number of subgroups");
  _p_writer->writeCell("Subgroup ids");

  for(MsRunSp &msrun_sp : _msrun_list)
    {
      if(_sp_labelling_method == nullptr)
        {
          _p_writer->writeCell(msrun_sp.get()->getSampleName());
        }
      else
        {
          for(const Label *p_label : _label_list)
            {
              _p_writer->writeCell(QString("%1-%2")
                                     .arg(msrun_sp.get()->getSampleName())
                                     .arg(p_label->getXmlId()));
            }
        }
    }
}


void
ComparSpectraByPeptide::writeIdentificationGroup(IdentificationGroup *p_ident)
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " begin";
  _p_current_identification_group = 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) {
                  return a->getGrpPeptideSp().get()->getRank() <
                         b->getGrpPeptideSp().get()->getRank();
                });

      const PeptideEvidence *p_best_peptide_evidence = nullptr;
      std::map<QString, std::vector<size_t>> sample_scan_list;

      for(auto &peptide_evidence : peptide_evidence_list)
        {
          if(p_best_peptide_evidence == nullptr)
            {
              p_best_peptide_evidence = peptide_evidence;
            }
          if(p_best_peptide_evidence->getGrpPeptideSp().get() !=
             peptide_evidence->getGrpPeptideSp().get())
            {
              // write p_best_peptide_match
              writeBestPeptideEvidence(group_pair.second.get(),
                                       p_best_peptide_evidence,
                                       sample_scan_list);
              sample_scan_list.clear();
              p_best_peptide_evidence = peptide_evidence;
            }
          else
            {
              if(p_best_peptide_evidence->getEvalue() >
                 peptide_evidence->getEvalue())
                {
                  p_best_peptide_evidence = peptide_evidence;
                }
            }

          QString key_sample;
          const Label *p_label =
            peptide_evidence->getPeptideXtpSp().get()->getLabel();
          if(p_label == nullptr)
            {
              key_sample = peptide_evidence->getMsRunP()->getXmlId();
            }
          else
            {
              key_sample = QString("%1-%2")
                             .arg(peptide_evidence->getMsRunP()->getXmlId())
                             .arg(p_label->getXmlId());
            }

          auto it = sample_scan_list.find(key_sample);
          if(it != sample_scan_list.end())
            {
              it->second.push_back(peptide_evidence->getHashSampleScan());
            }
          else
            {
              std::vector<size_t> one_element;
              one_element.push_back(peptide_evidence->getHashSampleScan());
              sample_scan_list.insert(std::pair<QString, std::vector<size_t>>(
                key_sample, one_element));
            }
          //_p_writer->writeCell(msrun_sp.get()->getSampleName());
          // sample_scan_list.push_back(peptide_evidence->getHashSampleScan());
        }

      if(p_best_peptide_evidence != nullptr)
        {
          writeBestPeptideEvidence(
            group_pair.second.get(), p_best_peptide_evidence, sample_scan_list);
          sample_scan_list.clear();
        }
    }

  if(!_first_cell_coordinate.isEmpty())
    {
      QString last_cell_coordinate = _p_writer->getOdsCellCoordinate();
      qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " "
               << _first_cell_coordinate << " " << last_cell_coordinate;
      OdsColorScale color_scale(_first_cell_coordinate, last_cell_coordinate);
      _p_writer->addColorScale(color_scale);
      _first_cell_coordinate = "";
    }
  _p_writer->writeLine();
  _p_writer->writeLine();
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << " end";
}


void
ComparSpectraByPeptide::writeBestPeptideEvidence(
  const GroupingGroup *p_group,
  const PeptideEvidence *p_peptide_evidence,
  const std::map<QString, std::vector<size_t>> &sample_scan_list)
{

  _p_writer->writeLine();


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

  _p_ods_export->setEvenOrOddStyle(group_number, _p_writer);
  _p_writer->writeCell(pappso::Utils::getLexicalOrderedString(group_number));
  _p_writer->clearTableCellStyleRef();
  _p_writer->writeCell(
    p_peptide_evidence->getGrpPeptideSp().get()->getGroupingId());
  _p_writer->writeCell(
    p_peptide_evidence->getGrpPeptideSp().get()->getSequence());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getModifString());
  _p_writer->writeCell((std::size_t)p_peptide_evidence->getCharge());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getNativePeptideP()->getMz(1));
  QStringList sg_list = p_group->getSubgroupIdList(p_peptide_evidence);
  _p_writer->writeCell(sg_list.size());
  _p_writer->writeCell(sg_list.join(" "));


  //_p_writer->writeCell((unsigned int)sample_scan_list.size());


  for(MsRunSp &msrun_sp : _msrun_list)
    {
      if(_label_list.size() == 0)
        {
          writeComparValue(
            sample_scan_list, ValidationState::validAndChecked, msrun_sp.get());
          if(_first_cell_coordinate.isEmpty())
            {
              _first_cell_coordinate = _p_writer->getOdsCellCoordinate();
            }
        }
      else
        {
          for(const Label *p_label : _label_list)
            {
              writeComparValue(sample_scan_list,
                               ValidationState::validAndChecked,
                               msrun_sp.get(),
                               p_label);
              if(_first_cell_coordinate.isEmpty())
                {
                  _first_cell_coordinate = _p_writer->getOdsCellCoordinate();
                }
            }
        }
    }
}


void
ComparSpectraByPeptide::writeComparValue(
  const std::map<QString, std::vector<size_t>> &sample_scan_list,
  ValidationState state [[maybe_unused]],
  const MsRun *p_msrun,
  const Label *p_label)
{
  /*
  std::sort(sample_scan_list.begin(), sample_scan_list.end());
  auto last = std::unique(sample_scan_list.begin(), sample_scan_list.end());
  sample_scan_list.erase(last, sample_scan_list.end());
*/

  QString key_sample;
  if(p_label == nullptr)
    {
      key_sample = p_msrun->getXmlId();
    }
  else
    {
      key_sample =
        QString("%1-%2").arg(p_msrun->getXmlId()).arg(p_label->getXmlId());
    }

  auto it = sample_scan_list.find(key_sample);
  if(it == sample_scan_list.end())
    {
      _p_writer->writeCell(0);
    }
  else
    {
      std::vector<size_t> new_list = it->second;
      std::sort(new_list.begin(), new_list.end());
      auto last = std::unique(new_list.begin(), new_list.end());
      new_list.erase(last, new_list.end());
      _p_writer->writeCell(new_list.size());
    }
}
