
/*******************************************************************************
 * 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 <QDebug>
#include <QSettings>
#include <pappsomspp/core/pappsoexception.h>
#include "ui_protein_view.h"
#include "proteintableproxymodel.h"
#include "proteintablemodel.h"
#include "proteinlistwindow.h"
#include "../../project_view/projectwindow.h"

ProteinTableProxyModel::ProteinTableProxyModel(
  ProteinListWindow *p_protein_list_window,
  ProteinTableModel *protein_table_model_p)
  : QSortFilterProxyModel(protein_table_model_p)
{
  _protein_table_model_p = protein_table_model_p;
  _p_protein_list_window = p_protein_list_window;
  _column_display.resize(30);
  QSettings settings;
  for(std::size_t i = 0; i < _column_display.size(); i++)
    {

      _column_display[i] =
        settings
          .value(QString("protein_list_columns/%1")
                   .arg(_protein_table_model_p->getTitle((ProteinListColumn)i)),
                 "true")
          .toBool();
    }

  _percent_delegate =
    new PercentItemDelegate(p_protein_list_window->ui->tableView);
}

ProteinTableProxyModel::~ProteinTableProxyModel()
{
  // delete _percent_delegate;
}
bool
ProteinTableProxyModel::filterAcceptsColumn(int source_column,
                                            const QModelIndex &source_parent
                                            [[maybe_unused]]) const
{
  return _column_display[source_column];
}

bool
ProteinTableProxyModel::filterAcceptsRow(int source_row,
                                         const QModelIndex &source_parent
                                         [[maybe_unused]]) const
{
  try
    {
      // qDebug() << "ProteinTableProxyModel::filterAcceptsRow begin " <<
      // source_row;
      ProteinMatch *protein_match =
        _protein_table_model_p->getIdentificationGroup()
          ->getProteinMatchList()
          .at(source_row);
      // qDebug() << "ProteinTableProxyModel::filterAcceptsRow protein_match "
      // << source_row;

      // qDebug() << "ProteinTableProxyModel::filterAcceptsRow valid ";
      if(_hide_not_valid)
        {
          if(!protein_match->isValid())
            {
              return false;
            }
        }
      // qDebug() << "ProteinTableProxyModel::filterAcceptsRow checked ";
      if(_hide_not_checked)
        {
          if(!protein_match->isChecked())
            {
              return false;
            }
        }

      // qDebug() << "ProteinTableProxyModel::filterAcceptsRow grouped ";
      pappso::GrpProtein *p_grp_prot = protein_match->getGrpProteinSp().get();
      if(_hide_not_grouped)
        {
          if(p_grp_prot == nullptr)
            {
              return false;
            }

          // qDebug() << "ProteinTableProxyModel::filterAcceptsRow grouped 2";
          if(p_grp_prot->getGroupingId().isEmpty())
            {
              return false;
            }
        }


      if(_search_on == "MS run/scan")
        {
          unsigned int scan_num =
            this->_p_protein_list_window->ui->scan_number_edit->value();
          QString file_search_string =
            this->_p_protein_list_window->ui->msrun_auto_completion->text()
              .toLower();
          qDebug() << " msrun/scan " << file_search_string << " " << scan_num;
          for(const PeptideMatch &p_peptide_match :
              protein_match->getPeptideMatchList())
            {
              bool scan_ok = true;
              if(scan_num > 0)
                {
                  scan_ok = false;
                  if(p_peptide_match.getPeptideEvidence()->getScanNumber() ==
                     scan_num)
                    {
                      scan_ok = true;
                    }
                }
              bool msrun_ok = true;
              if(!file_search_string.isEmpty())
                {
                  msrun_ok = false;
                  if(p_peptide_match.getPeptideEvidence()
                       ->getMsRunP()
                       ->getFileName()
                       .toLower()
                       .contains(file_search_string))
                    {
                      msrun_ok = true;
                    }
                }
              if(msrun_ok && scan_ok)
                {
                  return true;
                }
            }
          return false;
        }
      if(!_protein_search_string.isEmpty())
        {
          qDebug() << "search on " << _search_on << " : "
                   << _protein_search_string;
          if(_search_on == "Accession")
            {
              qDebug() << "search on " << _search_on << " : "
                       << _protein_search_string;
              if(!protein_match->getProteinXtpSp()
                    .get()
                    ->getAccession()
                    .contains(_protein_search_string))
                {
                  return false;
                }
            }
          else if(_search_on == "Group")
            {
              pappso::GrpProtein *p_grp_prot =
                protein_match->getGrpProteinSp().get();
              if(p_grp_prot == nullptr)
                {
                  return false;
                }
              else
                {
                  p_grp_prot->getGroupingId();
                  if(!p_grp_prot->getGroupingId().startsWith(
                       _protein_search_string))
                    {
                      return false;
                    }
                }
            }
          else if(_search_on == "Prot. seq.")
            {
              if(!protein_match->getProteinXtpSp()
                    .get()
                    ->getSequence()
                    .contains(_protein_search_string))
                {
                  return false;
                }
            }
          else if(_search_on == "Prot. seq. (L->I)")
            {
              QString peptide_search_string =
                QString(_protein_search_string).replace("L", "I");
              QString protein_sequence_li =
                QString(protein_match->getProteinXtpSp().get()->getSequence())
                  .replace("L", "I");
              if(!protein_sequence_li.contains(peptide_search_string))
                {
                  return false;
                }
            }
          else if(_search_on == "Pep. seq. (L->I)")
            {
              QString peptide_search_string =
                QString(_protein_search_string).replace("L", "I");
              for(const PeptideMatch &p_peptide_match :
                  protein_match->getPeptideMatchList())
                {
                  if(p_peptide_match.getPeptideEvidence()
                       ->getPeptideXtpSp()
                       .get()
                       ->getSequenceLi()
                       .contains(peptide_search_string))
                    {
                      return true;
                    }
                }
              return false;
            }
          else
            {
              qDebug() << "search on " << _search_on << " : "
                       << _protein_search_string;
              if(!protein_match->getProteinXtpSp()
                    .get()
                    ->getDescription()
                    .contains(_protein_search_string))
                {
                  return false;
                }
            }
        }


      if(_search_on == "Modifications")
        {
          QString mod_search_string =
            this->_p_protein_list_window->ui->mod_auto_completion->text();

          std::vector<pappso::AaModificationP> mod_list;
          for(pappso::AaModificationP mod :
              _p_protein_list_window->getProjectWindow()
                ->getProjectP()
                ->getPeptideStore()
                .getModificationCollection())
            {
              if(QString("[%1] %2 %3")
                   .arg(mod->getAccession())
                   .arg(mod->getName())
                   .arg(mod->getMass())
                   .contains(mod_search_string))
                {
                  mod_list.push_back(mod);
                }
              // qDebug() << "ProteinListWindow::setIdentificationGroup " <<
              // msrun_sp.get()->getFilename();
            }
          // qDebug() << "ProteinTableProxyModel::filterAcceptsRow msrun/scan "
          // << file_search_string << " " << scan_num;
          for(const PeptideMatch &p_peptide_match :
              protein_match->getPeptideMatchList())
            {
              for(pappso::AaModificationP mod : mod_list)
                {
                  if(p_peptide_match.getPeptideEvidence()
                       ->getPeptideXtpSp()
                       .get()
                       ->getNumberOfModification(mod) > 0)
                    {
                      return true;
                    }
                }
            }
          return false;
        }
    }

  catch(pappso::PappsoException &exception_pappso)
    {
      // QMessageBox::warning(this,
      //                     tr("Error in ProteinTableModel::acceptRow :"),
      //                     exception_pappso.qwhat());
      qDebug() << "Error in ProteinTableModel::acceptRow :"
               << exception_pappso.qwhat();
    }
  catch(std::exception &exception_std)
    {
      // QMessageBox::warning(this,
      //                    tr("Error in ProteinTableModel::acceptRow :"),
      //                    exception_std.what());
      qDebug() << "Error in ProteinTableModel::acceptRow :"
               << exception_std.what();
    }

  return true;

  // return true;
}


void
ProteinTableProxyModel::onTableClicked(const QModelIndex &index)
{
  qDebug() << " begin " << index.row();
  qDebug() << " begin " << this->mapToSource(index).row();

  //_protein_table_model_p->onTableClicked(this->mapToSource(index));
  QModelIndex source_index(this->mapToSource(index));
  int row               = source_index.row();
  ProteinListColumn col = (ProteinListColumn)source_index.column();
  ProteinMatch *p_protein_match =
    _protein_table_model_p->getIdentificationGroup()->getProteinMatchList().at(
      row);
  if(col == ProteinListColumn::checked) // add a checkbox to cell(1,0)
    {

      if(p_protein_match->isChecked())
        {
          p_protein_match->setChecked(false);
        }
      else
        {
          p_protein_match->setChecked(true);
        }
      _p_protein_list_window->edited();
    }
  else
    {
      if((col == ProteinListColumn::accession) ||
         (col == ProteinListColumn::description) ||
         (col == ProteinListColumn::coverage))
        {
          _p_protein_list_window->askProteinDetailView(p_protein_match);
        }
      else
        {
          _p_protein_list_window->askPeptideListView(p_protein_match);
        }
    }
  qDebug() << " end " << index.row();
}

bool
ProteinTableProxyModel::lessThan(const QModelIndex &left,
                                 const QModelIndex &right) const
{
  QVariant leftData  = sourceModel()->data(left);
  QVariant rightData = sourceModel()->data(right);
  if(leftData.typeId() == QMetaType::UInt)
    {
      return leftData.toUInt() < rightData.toUInt();
    }
  if(leftData.typeId() == QMetaType::UInt)
    {
      return leftData.toUInt() < rightData.toUInt();
    }
  if(leftData.typeId() == QMetaType::Double)
    {
      return leftData.toDouble() < rightData.toDouble();
    }
  return leftData.toString() < rightData.toString();
}

QVariant
ProteinTableProxyModel::data(const QModelIndex &index, int role) const
{

  return sourceModel()->data(mapToSource(index), role);
}

QVariant
ProteinTableProxyModel::headerData(int section,
                                   Qt::Orientation orientation,
                                   int role) const
{
  int col = mapToSource(index(0, section)).column();

  return sourceModel()->headerData(col, orientation, role);
}

void
ProteinTableProxyModel::hideNotValid(bool hide)
{
  _hide_not_valid = hide;
}

void
ProteinTableProxyModel::hideNotChecked(bool hide)
{
  qDebug() << " begin ";
  _hide_not_checked = hide;
  qDebug() << " end ";
}
void
ProteinTableProxyModel::hideNotGrouped(bool hide)
{
  _hide_not_grouped = hide;
}
void
ProteinTableProxyModel::setSearchOn(QString search_on)
{
  _search_on = search_on;
  qDebug() << " _search_on=" << _search_on;
  qDebug() << " _protein_search_string=" << _protein_search_string;
}

void
ProteinTableProxyModel::setMsrunFileSearch(QString msrun_file_search
                                           [[maybe_unused]])
{
}
void
ProteinTableProxyModel::setProteinSearchString(QString protein_search_string)
{
  _protein_search_string = protein_search_string;
  qDebug() << " _search_on=" << _search_on;
  qDebug() << " _protein_search_string=" << _protein_search_string;
}
void
ProteinTableProxyModel::setProteinListColumnDisplay(ProteinListColumn column,
                                                    bool toggled)
{
  qDebug() << " begin " << toggled;
  beginResetModel();
  QSettings settings;
  settings.setValue(QString("protein_list_columns/%1")
                      .arg(_protein_table_model_p->getTitle(column)),
                    toggled);

  _column_display[(std::int8_t)column] = toggled;
  endResetModel();

  resteItemDelegates();
}
bool
ProteinTableProxyModel::getProteinListColumnDisplay(
  ProteinListColumn column) const
{
  return _column_display[(std::int8_t)column];
}


void
ProteinTableProxyModel::resteItemDelegates() const
{

  for(int i = 0; i < columnCount(); ++i)
    {
      _p_protein_list_window->ui->tableView->setItemDelegateForColumn(
        i, _p_protein_list_window->ui->tableView->itemDelegate());
      if(mapToSource(index(0, i)).column() ==
         (std::int8_t)ProteinListColumn::coverage)
        {
          _p_protein_list_window->ui->tableView->setItemDelegateForColumn(
            i, _percent_delegate);
        }
    }
}
