/**
 * \file output/ods/peptidepossheet.cpp
 * \date 30/4/2017
 * \author Olivier Langella
 * \brief ODS peptide pos 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 "peptidepossheet.h"
#include <tuple>
#include <pappsomspp/core/utils.h>
#include <QDebug>


PeptidePosSheet::PeptidePosSheet(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;
  p_writer->writeSheet("peptide pos");

  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
PeptidePosSheet::writeHeaders(IdentificationGroup *p_ident)
{
  // Peptide ID	Protein ID	accession	description	Sequence	Modifs	Start	Stop
  // MH+ theo


  // 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("Subgroup ID");
  //_p_writer->setCellAnnotation("MS sample name (MS run)");
  _p_writer->writeCell("Protein ID");
  _p_writer->writeCell("accession");
  _p_writer->writeCell("description");
  writeCellHeader(PeptideListColumn::peptide_grouping_id);
  writeCellHeader(PeptideListColumn::sequence_nter);
  writeCellHeader(PeptideListColumn::sequence);
  writeCellHeader(PeptideListColumn::sequence_cter);
  _p_writer->writeCell("Number of spectra");
  writeCellHeader(PeptideListColumn::modifs);
  writeCellHeader(PeptideListColumn::start);
  _p_writer->writeCell("Stop");
  writeCellHeader(PeptideListColumn::theoretical_mhplus);
}

void
PeptidePosSheet::writeBestPeptideMatch(const ProteinMatch *p_protein_match,
                                       const PeptideMatch &peptide_match)
{

  _p_writer->writeLine();
  const PeptideEvidence *p_peptide_evidence =
    peptide_match.getPeptideEvidence();

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

  unsigned int group_number =
    p_protein_match->getGrpProteinSp().get()->getGroupNumber();
  unsigned int subgroup_number =
    p_protein_match->getGrpProteinSp().get()->getSubGroupNumber();
  unsigned int rank_number =
    p_protein_match->getGrpProteinSp().get()->getRank();

  _p_ods_export->setEvenOrOddStyle(group_number, _p_writer);
  _p_writer->writeCell(pappso::Utils::getLexicalOrderedString(group_number));
  _p_ods_export->setEvenOrOddStyle(subgroup_number, _p_writer);
  _p_writer->writeCell(pappso::Utils::getLexicalOrderedString(subgroup_number));
  _p_ods_export->setEvenOrOddStyle(rank_number, _p_writer);
  _p_writer->writeCell(
    p_protein_match->getGrpProteinSp().get()->getGroupingId());
  _p_writer->clearTableCellStyleRef();
  _p_writer->writeCell(
    p_protein_match->getProteinXtpSp().get()->getAccession());
  _p_writer->writeCell(
    p_protein_match->getProteinXtpSp().get()->getDescription());
  _p_writer->writeCell(
    p_peptide_evidence->getGrpPeptideSp().get()->getGroupingId());
  _p_writer->writeCell(
    p_protein_match->getFlankingNterRegion(peptide_match, 1));
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getSequence());
  _p_writer->writeCell(
    p_protein_match->getFlankingCterRegion(peptide_match, 1));
  _p_writer->writeCell(m_sample_scan_list.size());
  _p_writer->writeCell(
    p_peptide_evidence->getPeptideXtpSp().get()->getModifString());
  _p_writer->writeCell((std::size_t)peptide_match.getStart() + 1);
  _p_writer->writeCell((std::size_t)peptide_match.getStart() +
                       (std::size_t)p_peptide_evidence->getPeptideXtpSp()
                         .get()
                         ->getSequence()
                         .size());
  _p_writer->writeCell(p_peptide_evidence->getPeptideXtpSp().get()->getMz(1));
  m_sample_scan_list.clear();
}

void
PeptidePosSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{
  qDebug() << "PeptidePosSheet::writeIdentificationGroup begin";
  writeHeaders(p_ident);


  std::vector<ProteinMatch *> protein_match_list;

  for(ProteinMatch *p_protein_match : p_ident->getProteinMatchList())
    {
      if(p_protein_match->getValidationState() < ValidationState::grouped)
        continue;
      protein_match_list.push_back(p_protein_match);
    }

  std::sort(
    protein_match_list.begin(),
    protein_match_list.end(),
    [](const ProteinMatch *a, const ProteinMatch *b) {
      unsigned int agroup    = a->getGrpProteinSp().get()->getGroupNumber();
      unsigned int asubgroup = a->getGrpProteinSp().get()->getSubGroupNumber();
      unsigned int arank     = a->getGrpProteinSp().get()->getRank();
      unsigned int bgroup    = b->getGrpProteinSp().get()->getGroupNumber();
      unsigned int bsubgroup = b->getGrpProteinSp().get()->getSubGroupNumber();
      unsigned int brank     = b->getGrpProteinSp().get()->getRank();
      return std::tie(agroup, asubgroup, arank) <
             std::tie(bgroup, bsubgroup, brank);
    });

  for(ProteinMatch *p_protein_match : protein_match_list)
    {


      std::vector<PeptideMatch> peptide_match_list;

      for(auto &peptide_match : p_protein_match->getPeptideMatchList())
        {
          if(peptide_match.getPeptideEvidence()->getValidationState() <
             ValidationState::grouped)
            continue;
          peptide_match_list.push_back(peptide_match);
        }
      std::sort(peptide_match_list.begin(),
                peptide_match_list.end(),
                [](const PeptideMatch &a, const PeptideMatch &b) {
                  unsigned int arank =
                    a.getPeptideEvidence()->getGrpPeptideSp().get()->getRank();
                  unsigned int aposition = a.getStart();
                  unsigned int brank =
                    b.getPeptideEvidence()->getGrpPeptideSp().get()->getRank();
                  unsigned int bposition = b.getStart();
                  return std::tie(arank, aposition) <
                         std::tie(brank, bposition);
                });

      const PeptideMatch *p_best_peptide_match = nullptr;
      m_sample_scan_list.clear();

      for(auto &peptide_match : peptide_match_list)
        {
          const PeptideEvidence *p_peptide_evidence =
            peptide_match.getPeptideEvidence();

          if(p_best_peptide_match == nullptr)
            {
              p_best_peptide_match = &peptide_match;
            }
          // change spectra :
          unsigned int arank = p_best_peptide_match->getPeptideEvidence()
                                 ->getGrpPeptideSp()
                                 .get()
                                 ->getRank();
          unsigned int aposition = p_best_peptide_match->getStart();
          unsigned int brank     = peptide_match.getPeptideEvidence()
                                 ->getGrpPeptideSp()
                                 .get()
                                 ->getRank();
          unsigned int bposition = peptide_match.getStart();

          if(std::tie(arank, aposition) != std::tie(brank, bposition))
            {
              // write p_best_peptide_match
              writeBestPeptideMatch(p_protein_match, *p_best_peptide_match);
              p_best_peptide_match = &peptide_match;
            }
          else
            {
              if(p_best_peptide_match->getPeptideEvidence()->getEvalue() >
                 peptide_match.getPeptideEvidence()->getEvalue())
                {
                  p_best_peptide_match = &peptide_match;
                }
            }
          m_sample_scan_list.push_back(p_peptide_evidence->getHashSampleScan());
        }

      if(p_best_peptide_match != nullptr)
        {
          writeBestPeptideMatch(p_protein_match, *p_best_peptide_match);
        }
    }
  _p_writer->writeLine();
  _p_writer->writeLine();
  qDebug() << "PeptidePosSheet::writeIdentificationGroup end";
}


void
PeptidePosSheet::writeCellHeader(PeptideListColumn column)
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
           << (std::int8_t)column;
  _p_writer->setCellAnnotation(PeptideTableModel::getDescription(column));
  _p_writer->writeCell(PeptideTableModel::getTitle(column));
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}
