/**
 * \file output/ods/proteinsheet.h
 * \date 24/4/2017
 * \author Olivier Langella
 * \brief ODS protein sheet
 */

/*******************************************************************************
 * Copyright (c) 2017 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/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "proteinsheet.h"
#include "../../core/identificationgroup.h"
#include <pappsomspp/utils.h>
#include <pappsomspp/pappsoexception.h>

ProteinSheet::ProteinSheet(OdsExport *p_ods_export,
                           CalcWriterInterface *p_writer,
                           const Project *p_project)
  : _p_project(p_project)
{
  _p_writer     = p_writer;
  _p_ods_export = p_ods_export;
  p_writer->writeSheet("proteins");

  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
ProteinSheet::writeCellHeader(ProteinListColumn column)
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
           << (std::int8_t)column;
  _p_writer->setCellAnnotation(ProteinTableModel::getDescription(column));
  _p_writer->writeCell(ProteinTableModel::getTitle(column));
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}

void
ProteinSheet::writeHeaders(IdentificationGroup *p_ident)
{
  // Group ID Sub-group ID Protein ID Description log(E value)
  // Coverage MW Spectra Specific uniques Uniques PAI Redundancy

  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->setCellAnnotation("group number");
  _p_writer->writeCell("Group ID");
  _p_writer->setCellAnnotation("subgroup number");
  _p_writer->writeCell("Sub-group ID");

  _p_writer->setCellAnnotation(
    ProteinTableModel::getDescription(ProteinListColumn::protein_grouping_id));
  _p_writer->writeCell("Protein ID");
  // writeCellHeader(ProteinListColumn::protein_grouping_id);
  //_p_writer->setCellAnnotation("unique protein identifier within this grouping
  // experiment"); _p_writer->writeCell("Protein ID");

  writeCellHeader(ProteinListColumn::accession);
  writeCellHeader(ProteinListColumn::description);
  writeCellHeader(ProteinListColumn::log_evalue);
  writeCellHeader(ProteinListColumn::coverage);
  _p_writer->setCellAnnotation(
    "computed molecular weight for this protein (sum of amino acid masses)");
  _p_writer->writeCell("MW");
  _p_writer->setCellAnnotation("number of amino acids");
  _p_writer->writeCell("size");

  writeCellHeader(ProteinListColumn::spectrum);
  //_p_writer->setCellAnnotation("number of scans (spectra) attributed to this
  // protein");
  // _p_writer->writeCell("Spectra");
  writeCellHeader(ProteinListColumn::specific_spectrum);

  writeCellHeader(ProteinListColumn::sequence);

  writeCellHeader(ProteinListColumn::specific_sequence);
  _p_writer->setCellAnnotation(
    "number of unique peptidesequenceLI+modification+charge attributed to this "
    "protein (used to compute the PAI)");
  _p_writer->writeCell("Uniques peptide-mod-charge");
  _p_writer->setCellAnnotation(
    "theoretical number of tryptic peptides used in the PAI computation");
  _p_writer->writeCell("Theoretical number of tryptic peptides");

  writeCellHeader(ProteinListColumn::pai);
  writeCellHeader(ProteinListColumn::empai);
  //_p_writer->writeCell("spectral count AI");
  _p_writer->setCellAnnotation("number of proteins in the same subgroup");
  _p_writer->writeCell("Sub-group proteins");
  _p_writer->setCellAnnotation(
    "number of MS samples in which this protein was observed");
  _p_writer->writeCell("number of MS samples");
}

void
ProteinSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{

  writeHeaders(p_ident);
  for(const std::pair<unsigned int, GroupingGroupSp> &group_pair :
      p_ident->getGroupStore().getGroupMap())
    {

      std::vector<const ProteinMatch *> protein_match_list =
        group_pair.second.get()->getProteinMatchList();

      std::sort(protein_match_list.begin(),
                protein_match_list.end(),
                [](const ProteinMatch *a, const ProteinMatch *b) {
                  return a->getGrpProteinSp().get()->getGroupingId() <
                         b->getGrpProteinSp().get()->getGroupingId();
                });

      for(auto &protein_match : protein_match_list)
        {
          writeOneProtein(group_pair.second.get(), protein_match);
        }
    }
  _p_writer->writeLine();
}


void
ProteinSheet::writeOneProtein(const GroupingGroup *p_group,
                              const ProteinMatch *p_protein_match)
{
  try
    {
      _p_writer->writeLine();

      qDebug() << "ProteinSheet::writeOneProtein begin";
      ValidationState validation_state = ValidationState::validAndChecked;

      pappso::GrpProtein *p_grp_protein =
        p_protein_match->getGrpProteinSp().get();

      ProteinXtp *p_protein = p_protein_match->getProteinXtpSp().get();

      unsigned int group_number    = p_grp_protein->getGroupNumber();
      unsigned int subgroup_number = p_grp_protein->getSubGroupNumber();
      _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(
        QString("%1.%2")
          .arg(pappso::Utils::getLexicalOrderedString(group_number))
          .arg(pappso::Utils::getLexicalOrderedString(subgroup_number)));
      _p_writer->clearTableCellStyleRef();
      _p_writer->writeCell(p_grp_protein->getGroupingId());

      const std::list<DbXref> &dbxref_list = p_protein->getDbxrefList();
      if(dbxref_list.size() == 0)
        {
          _p_writer->writeCell(p_protein->getAccession());
        }
      else
        {
          _p_writer->writeCell(dbxref_list.front().getUrl(),
                               p_protein->getAccession());
        }
      _p_writer->writeCell(p_protein->getDescription());
      _p_writer->writeCell(p_protein_match->getLogEvalue());
      // _p_writer->writeCell("Coverage");
      _p_writer->writeCellPercentage(p_protein_match->getCoverage());
      // _p_writer->writeCell("MW");
      _p_writer->writeCell(p_protein->getMass());
      _p_writer->writeCell((std::size_t)p_protein->size());
      // _p_writer->writeCell("Spectra");
      _p_writer->writeCell(p_protein_match->countSampleScan(validation_state));

      // _p_writer->writeCell("Specific");
      _p_writer->writeCell(
        p_group->countSpecificSampleScan(p_protein_match, validation_state));

      // _p_writer->writeCell("Uniques");
      _p_writer->writeCell(p_protein_match->countSequenceLi(validation_state));

      // _p_writer->writeCell("Specific uniques");
      _p_writer->writeCell(
        p_group->countSpecificSequenceLi(p_protein_match, validation_state));


      _p_writer->writeCell(
        p_protein_match->countPeptideMassCharge(validation_state));
      qDebug() << "ProteinSheet::writeOneProtein tryptic";
      _p_writer->writeCell(p_protein->countTrypticPeptidesForPAI());
      // _p_writer->writeCell("PAI");
      // _p_writer->writeCell(new Double((float) hashProt
      // .getTotalHashSampleScan() / prot.get_PAI_count()));
      _p_writer->writeCell(p_protein_match->getPAI());
      // _p_writer->writeCell(match.getPAI());//this is the same
      /*
       * ancien PAI _p_writer->writeCell(new Double((float)
       * top.get_spectra_numbers_to(sample) /
       * top.get_protein_match().get_PAI_count()));
       */
      _p_writer->writeCell(p_protein_match->getEmPAI());

      //_p_writer->writeCell(p_protein_match->getSpectralCountAI());

      // _p_writer->writeCell("Redundancy");
      _p_writer->writeCell((std::size_t)p_group->countProteinInSubgroup(
        p_grp_protein->getSubGroupNumber()));

      // number of MS sample
      _p_writer->writeCell(
        (std::size_t)p_protein_match->countDistinctMsSamples(validation_state));

      qDebug() << "ProteinSheet::writeOneProtein end";
    }
  catch(pappso::PappsoException &error)
    {
      throw pappso::PappsoException(
        QObject::tr("Error writing protein %1 :\n%2")
          .arg(p_protein_match->getProteinXtpSp().get()->getAccession())
          .arg(error.qwhat()));
    }
}
