/**
 * \file output/ods/comparbasesheet.cpp
 * \date 2/5/2017
 * \author Olivier Langella
 * \brief ODS compar base 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/>.
 *
 ******************************************************************************/

#include "comparbasesheet.h"

#include <tuple>
#include <pappsomspp/core/utils.h>
#include <QDebug>
#include <pappsomspp/core/exception/exceptioninterrupted.h>


ComparBaseSheet::ComparBaseSheet(OdsExport *p_ods_export,
                                 CalcWriterInterface *p_writer,
                                 const Project *p_project,
                                 SubMonitor &sub_monitor)
  : _p_project(p_project), m_subMonitor(sub_monitor)
{
  _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
ComparBaseSheet::writeSheet()
{
  _p_writer->writeSheet(_title_sheet);

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

  qDebug();

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

  qDebug();

  //_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");
  _p_writer->writeCell("Number of proteins");

  qDebug();

  std::size_t total = _msrun_list.size();
  std::size_t i     = 0;
  for(MsRunSp &msrun_sp : _msrun_list)
    {
      m_subMonitor.setStatus(
        QObject::tr("writing %1 MSrun informations (%2 on %3)")
          .arg(msrun_sp.get()->getRunId())
          .arg(i + 1)
          .arg(total));
      qDebug();
      if(m_subMonitor.shouldIstop())
        {
          throw pappso::ExceptionInterrupted(
            QObject::tr("ODS compar sheet writing interrupted"));
        }
      qDebug();
      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()));
            }
        }
      i++;
    }
  qDebug();
}

void
ComparBaseSheet::writeProteinMatch(const ProteinMatch *p_protein_match)
{
  qDebug() << " begin";
  _p_writer->writeLine();


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

  if(_p_ods_export != nullptr)
    {
      _p_ods_export->setEvenOrOddStyle(group_number, _p_writer);
    }
  _p_writer->writeCell(pappso::Utils::getLexicalOrderedString(group_number));
  if(_p_ods_export != nullptr)
    {
      _p_ods_export->setEvenOrOddStyle(subgroup_number, _p_writer);
    }
  //_p_writer->writeCell(pappso::Utils::getLexicalOrderedString(subgroup_number));
  _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_protein_match->getGrpProteinSp().get()->getGroupingId());
  _p_writer->writeCell(
    p_protein_match->getProteinXtpSp().get()->getAccession());
  _p_writer->writeCell(
    p_protein_match->getProteinXtpSp().get()->getDescription());

  _p_writer->writeCell((std::size_t)p_protein_match->getGroupingGroupSp()
                         .get()
                         ->countProteinInSubgroup(subgroup_number));

  for(MsRunSp &msrun_sp : _msrun_list)
    {
      if(_label_list.size() == 0)
        {
          writeComparValue(
            p_protein_match, 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(p_protein_match,
                               ValidationState::validAndChecked,
                               msrun_sp.get(),
                               p_label);
              if(_first_cell_coordinate.isEmpty())
                {
                  _first_cell_coordinate = _p_writer->getOdsCellCoordinate();
                }
            }
        }
    }


  qDebug() << " end";
}

void
ComparBaseSheet::writeIdentificationGroup(IdentificationGroup *p_ident)
{
  qDebug() << " begin";
  _p_current_identification_group = p_ident;
  writeHeaders(p_ident);


  qDebug();
  std::vector<ProteinMatch *> protein_match_list;

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

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

  for(ProteinMatch *p_protein_match : protein_match_list)
    {
      writeProteinMatch(p_protein_match);
    }
  qDebug();


  if(!_first_cell_coordinate.isEmpty())
    {
      QString last_cell_coordinate = _p_writer->getOdsCellCoordinate();
      qDebug() << " " << _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() << " end";
}
