
/*******************************************************************************
 * 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 "proteintablemodel.h"
#include <pappsomspp/grouping/grpprotein.h>
#include "../../grouping/groupinggroup.h"

#include <QDebug>
#include <pappsomspp/pappsoexception.h>
#include "proteinlistwindow.h"
#include "../../utils/types.h"

IdentificationGroup *
ProteinTableModel::getIdentificationGroup()
{
  return _p_identification_group;
}
ProteinTableModel::ProteinTableModel(ProteinListWindow *p_protein_list_window)
  : QAbstractTableModel(p_protein_list_window)
{
  _p_protein_list_window  = p_protein_list_window;
  _p_identification_group = nullptr;
}

void
ProteinTableModel::setIdentificationGroup(
  IdentificationGroup *p_identification_group)
{
  qDebug() << "ProteinTableModel::setIdentificationGroup begin "
           << p_identification_group->getProteinMatchList().size();
  beginResetModel();
  _p_identification_group = p_identification_group;

  // emit headerDataChanged(Qt::Horizontal, 0,11);
  // refresh();
  qDebug() << "ProteinTableModel::setIdentificationGroup end ";
  endResetModel();

  _p_protein_list_window->resizeColumnsToContents();
}


int
ProteinTableModel::rowCount(const QModelIndex &parent [[maybe_unused]]) const
{
  // qDebug() << "ProteinTableModel::rowCount begin ";
  if(_p_identification_group != nullptr)
    {
      // qDebug() << "ProteinTableModel::rowCount(const QModelIndex &parent ) "
      // << _p_identification_group->getProteinMatchList().size();
      return (int)_p_identification_group->getProteinMatchList().size();
    }
  return 0;
}
int
ProteinTableModel::columnCount(const QModelIndex &parent [[maybe_unused]]) const
{
  // qDebug() << "ProteinTableModel::columnCount begin ";
  if(_p_identification_group != nullptr)
    {
      return 14;
    }
  return 0;
}
const QString
ProteinTableModel::getTitle(ProteinListColumn column)
{
  qDebug() << "ProteinTableModel::getTitle begin ";
  return ProteinTableModel::getTitle((std::int8_t)column);
  // qDebug() << "ProteinTableModel::getTitle end ";
}
const QString
ProteinTableModel::getDescription(ProteinListColumn column)
{
  qDebug() << "ProteinTableModel::columnCount begin ";
  return ProteinTableModel::getDescription((std::int8_t)column);
  // qDebug() << "ProteinTableModel::columnCount end ";
}

const QString
ProteinTableModel::getTitle(std::int8_t column)
{

  qDebug() << "ProteinTableModel::getTitle begin " << column;
  switch(column)
    {

      case(std::int8_t)ProteinListColumn::checked:
        return "checked";
        break;

      case(std::int8_t)ProteinListColumn::protein_grouping_id:
        return "group";
        break;
      case(std::int8_t)ProteinListColumn::accession:
        return "accession";
        break;
      case(std::int8_t)ProteinListColumn::description:
        return "description";
        break;
      case(std::int8_t)ProteinListColumn::log_evalue:
        return "log(Evalue)";
        break;
      case(std::int8_t)ProteinListColumn::evalue:
        return "Evalue";
        break;
      case(std::int8_t)ProteinListColumn::spectrum:
        return "spectra";
        break;
      case(std::int8_t)ProteinListColumn::specific_spectrum:
        return "specific spectra";
        break;
      case(std::int8_t)ProteinListColumn::sequence:
        return "sequences";
        break;
      case(std::int8_t)ProteinListColumn::coverage:
        return "coverage";
        break;
      case(std::int8_t)ProteinListColumn::pai:
        return "PAI";
        break;
      case(std::int8_t)ProteinListColumn::empai:
        return "emPAI";
        break;
      case(std::int8_t)ProteinListColumn::specific_sequence:
        return "specific sequences";
      case(std::int8_t)ProteinListColumn::molecular_weight:
        return "MW";
        break;
    }
  return "";
}

const QString
ProteinTableModel::getDescription(std::int8_t column)
{

  qDebug() << "ProteinTableModel::getDescription begin " << column;
  switch(column)
    {

      case(std::int8_t)ProteinListColumn::checked:
        return "manual protein check";
        break;

      case(std::int8_t)ProteinListColumn::protein_grouping_id:
        return "unique protein identifier within this grouping experiment";
        break;
      case(std::int8_t)ProteinListColumn::accession:
        return "protein accession";
        break;
      case(std::int8_t)ProteinListColumn::description:
        return "protein description";
        break;
      case(std::int8_t)ProteinListColumn::log_evalue:
        return "log(Evalue)";
        break;
      case(std::int8_t)ProteinListColumn::evalue:
        return "protein Evalue";
        break;
      case(std::int8_t)ProteinListColumn::spectrum:
        return "number of distinct MS spectrum assigned to this protein";
        break;
      case(std::int8_t)ProteinListColumn::specific_spectrum:
        return "number of distinct MS spectrum only assigned to this protein "
               "within the group";
        break;
      case(std::int8_t)ProteinListColumn::sequence:
        return "number of unique distinct peptide sequences";
        break;
      case(std::int8_t)ProteinListColumn::coverage:
        return "protein coverage (ratio)";
        break;
      case(std::int8_t)ProteinListColumn::pai:
        return "Protein Abundance Index (Rappsilber et al. 2002)";
        break;
      case(std::int8_t)ProteinListColumn::empai:
        return "Exponentially Modified Protein Abundance Index (emPAI) as "
               "described by Ishihama 2005";
        break;
      case(std::int8_t)ProteinListColumn::specific_sequence:
        return "number of unique distinct peptide sequences only assigned to "
               "this protein within the group";

      case(std::int8_t)ProteinListColumn::molecular_weight:
        return "protein molecular weight in Dalton";
    }
  return "";
}
QVariant
ProteinTableModel::headerData(int section,
                              Qt::Orientation orientation,
                              int role) const
{
  if(_p_identification_group == nullptr)
    return QVariant();
  if(orientation == Qt::Horizontal)
    {
      switch(role)
        {
          case Qt::DisplayRole:
            return QVariant(getTitle(section));
            break;
          case Qt::ToolTipRole:
            return QVariant(getDescription(section));
            break;
          case Qt::SizeHintRole:
            // qDebug() << "ProteinTableModel::headerData " <<
            // ProteinTableModel::getColumnWidth(section);
            return QSize(ProteinTableModel::getColumnWidth(section), 40);
            break;
        }
    }
  return QVariant();
}

int
ProteinTableModel::getColumnWidth(int column)
{
  qDebug() << "ProteinTableModel::getColumnWidth " << column;
  switch(column)
    {

      case(int)ProteinListColumn::checked:
        break;

      case(int)ProteinListColumn::protein_grouping_id:
        return 120;
        break;
      case(int)ProteinListColumn::accession:
        qDebug() << "ProteinTableModel::getColumnWidth accession " << column;
        return 250;
        break;
      case(int)ProteinListColumn::description:
        return 400;
        break;
    }
  return 100;
}

ProteinListColumn
ProteinTableModel::getProteinListColumn(std::int8_t column)
{
  return static_cast<ProteinListColumn>(column);
}

QVariant
ProteinTableModel::data(const QModelIndex &index, int role) const
{
  // generate a log message when this method gets called
  if(_p_identification_group == nullptr)
    return QVariant();
  int row = index.row();
  int col = index.column();
  // qDebug() << QString("row %1, col%2, role %3")
  //          .arg(row).arg(col).arg(role);

  switch(role)
    {
      case Qt::CheckStateRole:

        if(col == 0) // add a checkbox to cell(1,0)
          {
            if(_p_identification_group->getProteinMatchList()
                 .at(row)
                 ->isChecked())
              {
                return Qt::Checked;
              }
            else
              {
                return Qt::Unchecked;
              }
          }
        break;
      case Qt::SizeHintRole:
        // qDebug() << "ProteinTableModel::headerData " <<
        // ProteinTableModel::getColumnWidth(section);
        return QSize(ProteinTableModel::getColumnWidth(col), 30);
        break;
      case Qt::BackgroundRole:
        if(_p_identification_group->getProteinMatchList().at(row)->isValid() ==
           false)
          {
            return QVariant(QColor("grey"));
          }
        if(_p_identification_group->getProteinMatchList()
             .at(row)
             ->getProteinXtpSp()
             .get()
             ->isDecoy() == true)
          {
            return QVariant(QColor("orange"));
          }
        if(_p_identification_group->getProteinMatchList()
             .at(row)
             ->getProteinXtpSp()
             .get()
             ->isContaminant() == true)
          {
            return QVariant(QColor("orange"));
          }
        break;
      case Qt::DisplayRole:
        if(_p_identification_group == nullptr)
          {
            return QVariant();
          }
        switch(col)
          {
            case(std::int8_t)ProteinListColumn::checked:
              return QVariant();
              break;

            case(std::int8_t)ProteinListColumn::protein_grouping_id:
              pappso::GrpProtein *p_grp_prot =
                _p_identification_group->getProteinMatchList()
                  .at(row)
                  ->getGrpProteinSp()
                  .get();
              if(p_grp_prot != nullptr)
                return p_grp_prot->getGroupingId();
              return QVariant();
              break;
          }
        if(col == (std::int8_t)ProteinListColumn::accession)
          {
            return QVariant(_p_identification_group->getProteinMatchList()
                              .at(row)
                              ->getProteinXtpSp()
                              .get()
                              ->getAccession());
          }

        if(col == (std::int8_t)ProteinListColumn::description)
          {
            return _p_identification_group->getProteinMatchList()
              .at(row)
              ->getProteinXtpSp()
              .get()
              ->getDescription();
          }
        if(col == (std::int8_t)ProteinListColumn::log_evalue)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getLogEvalue());
          }

        if(col == (std::int8_t)ProteinListColumn::evalue)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getEvalue());
          }
        if(col == (std::int8_t)ProteinListColumn::spectrum)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->countSampleScan(ValidationState::validAndChecked));
          }

        if(col == (std::int8_t)ProteinListColumn::specific_spectrum)
          {
            GroupingGroup *p_groupin_group =
              _p_identification_group->getProteinMatchList()
                .at(row)
                ->getGroupingGroupSp()
                .get();
            if(p_groupin_group != nullptr)
              {
                return QVariant((qreal)p_groupin_group->countSpecificSampleScan(
                  _p_identification_group->getProteinMatchList().at(row),
                  ValidationState::validAndChecked));
              }
          }

        if(col == (std::int8_t)ProteinListColumn::sequence)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->countSequenceLi(ValidationState::validAndChecked));
          }
        if(col == (std::int8_t)ProteinListColumn::specific_sequence)
          {
            GroupingGroup *p_groupin_group =
              _p_identification_group->getProteinMatchList()
                .at(row)
                ->getGroupingGroupSp()
                .get();
            if(p_groupin_group != nullptr)
              {
                return QVariant((qreal)p_groupin_group->countSpecificSequenceLi(
                  _p_identification_group->getProteinMatchList().at(row),
                  ValidationState::validAndChecked));
              }
          }
        if(col == (std::int8_t)ProteinListColumn::coverage)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getCoverage());
          }

        if(col == (std::int8_t)ProteinListColumn::pai)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getPAI());
          }
        if(col == (std::int8_t)ProteinListColumn::empai)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getEmPAI());
          }
        if(col == (std::int8_t)ProteinListColumn::molecular_weight)
          {
            return QVariant(
              (qreal)_p_identification_group->getProteinMatchList()
                .at(row)
                ->getProteinXtpSp()
                .get()
                ->getMass());
          }
        return QVariant();
    }
  return QVariant();
}

void
ProteinTableModel::onProteinDataChanged()
{
  qDebug() << "ProteinTableModel::onProteinDataChanged begin " << rowCount();
  emit layoutAboutToBeChanged();
  emit layoutChanged();
}
