/**
 * \file /output/ods/ptm/ptmislandsheet.cpp
 * \date 3/5/2017
 * \author Olivier Langella
 * \brief ODS PTM island 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 "ptmislandsheet.h"

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

PtmIslandSheet::PtmIslandSheet(OdsExport *p_ods_export,
                               CalcWriterInterface *p_writer,
                               const Project *p_project)
  : _p_project(p_project)
{
  qDebug();
  _p_writer     = p_writer;
  _p_ods_export = p_ods_export;
  p_writer->writeSheet("PTM islands");

  std::vector<IdentificationGroup *> identification_list =
    p_project->getIdentificationGroupList();
  for(IdentificationGroup *p_ident : identification_list)
    {
      // writeHeaders(p_ident);
      _p_ptm_grouping_experiment = p_ident->getPtmGroupingExperiment();
      if(_p_ptm_grouping_experiment == nullptr)
        {
          const std::vector<MsRunSp> &ms_run_list = p_ident->getMsRunSpList();
          if(ms_run_list.size() > 0)
            {
              throw pappso::PappsoException(
                QObject::tr("Error writing PTM island :\nperhaps ptm grouping "
                            "was not done on sample %1")
                  .arg(ms_run_list.front().get()->getSampleName()));
            }
        }
      writeIdentificationGroup(p_ident);
    }
  qDebug();
}

void
PtmIslandSheet::writeCellHeader(PtmIslandListColumn column)
{
  qDebug() << "PtmIslandSheet::writeCellHeader begin " << (std::int8_t)column;
  _p_writer->setCellAnnotation(PtmIslandTableModel::getDescription(column));
  _p_writer->writeCell(PtmIslandTableModel::getTitle(column));
  qDebug() << "PtmIslandSheet::writeCellHeader end";
}

void
PtmIslandSheet::writeHeaders(IdentificationGroup *p_ident)
{

  // ptm

  // Group ID	Sub-group ID	PhosphoIsland ID	Description	MW	Phosphosites
  // positions	Spectra	Uniques	number of proteins sharing these phosphosites a1
  // a1.a1	a1.a1.a1	AT1G01100.1 | Symbols:  | 60S acidic ribosomal protein
  // family | chr1:50284-50954 REVERSE LENGTH=112	11,1000003814697	102	435	3	6
  qDebug() << "PtmIslandSheet::writeHeaders begin";
  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("PTM group number");
  _p_writer->writeCell("PTM group ID");
  _p_writer->setCellAnnotation("PTM subgroup number");
  _p_writer->writeCell("PTM sub-group ID");
  writeCellHeader(PtmIslandListColumn::ptm_island_id);
  //_p_writer->PtmIslandListColumn("unique protein identifier within this
  // grouping experiment"); _p_writer->writeCell("Protein ID");

  writeCellHeader(PtmIslandListColumn::accession);
  writeCellHeader(PtmIslandListColumn::description);
  _p_writer->setCellAnnotation(
    "computed molecular weight for this protein (sum of amino acid masses)");
  _p_writer->writeCell("MW");
  writeCellHeader(PtmIslandListColumn::ptm_position_list);

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

  _p_writer->setCellAnnotation("Number of proteins sharing this PTM island");
  _p_writer->writeCell("Number of proteins");

  qDebug() << "PtmIslandSheet::writeHeaders end";
}

void
PtmIslandSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{

  qDebug();
  _p_ptm_grouping_experiment = p_ident->getPtmGroupingExperiment();
  if(_p_ptm_grouping_experiment == nullptr)
    {
      throw pappso::PappsoException(QObject::tr(
        "Error writing PTM island :\n_p_ptm_grouping_experiment = nullptr"));
    }
  writeHeaders(p_ident);

  qDebug();
  std::vector<PtmIslandSp> ptm_island_list;
  for(auto ptm_island_sp : _p_ptm_grouping_experiment->getPtmIslandList())
    {
      qDebug();
      if(ptm_island_sp->isChecked())
      {
        ptm_island_list.push_back(ptm_island_sp);
      }
    }
  qDebug();
  std::sort(ptm_island_list.begin(),
            ptm_island_list.end(),
            [](PtmIslandSp &a, PtmIslandSp &b) {
              return a.get()->getGroupingId() < b.get()->getGroupingId();
            });

  qDebug();
  for(auto &ptm_island : ptm_island_list)
    {
      writeOnePtmIsland(ptm_island);
    }


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


void
PtmIslandSheet::writeOnePtmIsland(PtmIslandSp &sp_ptm_island)
{
  try
    {
      _p_writer->writeLine();

      qDebug() << "PtmIslandSheet::writeOnePtmIsland begin";
      // ValidationState validation_state = ValidationState::validAndChecked;

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

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

      const PtmIslandSubgroup *p_ptm_island_subgroup =
        sp_ptm_island.get()->getPtmIslandSubroup();
      const PtmIslandGroup *p_ptm_island_group =
        p_ptm_island_subgroup->getPtmIslandGroup();
      unsigned int group_number    = p_ptm_island_group->getGroupNumber();
      unsigned int subgroup_number = p_ptm_island_subgroup->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(sp_ptm_island.get()->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->getMass());

      QStringList position_list;
      for(unsigned int position : sp_ptm_island.get()->getPositionList())
        {
          position_list << QString("%1").arg(position + 1);
        }
      _p_writer->writeCell(position_list.join(" "));
      // _p_writer->writeCell("Spectra");
      _p_writer->writeCell(
        sp_ptm_island.get()->getPtmIslandSubroup()->countSampleScan());
      _p_writer->writeCell(sp_ptm_island.get()->countSampleScanWithPtm(
        _p_ptm_grouping_experiment));
      // _p_writer->writeCell("Uniques");
      _p_writer->writeCell(sp_ptm_island.get()->countSequence());
      _p_writer->writeCell(
        sp_ptm_island.get()->getPtmIslandSubroup()->getPtmIslandList().size());


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