
/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.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@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "proteinlistwindow.h"

#include "ui_protein_view.h"
#include "../../mainwindow.h"
#include <QSettings>
#include <odsstream/odsdocwriter.h>
#include <odsstream/qtablewriter.h>

ProteinListQactionColumn::ProteinListQactionColumn(ProteinListWindow *parent,
                                                   ProteinListColumn column)
  : QAction(parent)
{

  this->setText(ProteinTableModel::getTitle(column));

  this->setCheckable(true);
  this->setChecked(parent->getProteinListColumnDisplay(column));


  // evalue_action.setChecked(_display_evalue);
  // connect(p_action, SIGNAL(toggled(bool)), this,
  // SLOT(showEvalueColumn(bool)));
  _column                = column;
  _p_protein_list_window = parent;

  connect(this,
          &ProteinListQactionColumn::toggled,
          this,
          &ProteinListQactionColumn::doToggled);
}

ProteinListQactionColumn::~ProteinListQactionColumn()
{
  // if (_p_ms_data_file != nullptr) delete _p_ms_data_file;
  qDebug();
}
void
ProteinListQactionColumn::doToggled(bool toggled)
{
  qDebug() << "toggled=" << toggled;
  setChecked(toggled);
  _p_protein_list_window->setProteinListColumnDisplay(_column, toggled);

  qDebug();
}

ProteinListWindow::ProteinListWindow(ProjectWindow *parent)
  : QMainWindow(parent), ui(new Ui::ProteinView)
{
  qDebug();
  _project_window = parent;
  ui->setupUi(this);
  setWindowIcon(QIcon(":/i2masschroq_icon/resources/i2MassChroQ_icon.svg"));
  /*
   */
  _protein_table_model_p = new ProteinTableModel(this);

  if(_project_window->getProjectP() != nullptr)
    {
      setWindowTitle(QString("%1 - Protein list")
                       .arg(_project_window->getProjectP()->getProjectName()));
    }
  _p_proxy_model = new ProteinTableProxyModel(this, _protein_table_model_p);
  _p_proxy_model->setSourceModel(_protein_table_model_p);
  _p_proxy_model->setDynamicSortFilter(true);
  ui->tableView->setModel(_p_proxy_model);
  ui->tableView->setSortingEnabled(true);
  ui->tableView->horizontalHeader()->setSectionsMovable(true);
  ui->tableView->setAlternatingRowColors(true);

  QSettings settings;
  bool hide = settings.value("proteinview/hidenotvalid", "true").toBool();
  ui->actionValid_proteins->setChecked(hide);
  _p_proxy_model->hideNotValid(hide);
  hide = settings.value("proteinview/hidenotchecked", "false").toBool();
  ui->actionChecked_proteins->setChecked(hide);
  _p_proxy_model->hideNotChecked(hide);
  hide = settings.value("proteinview/hidenotgrouped", "false").toBool();
  ui->actionGrouped_proteins->setChecked(hide);
  _p_proxy_model->hideNotGrouped(hide);


  ui->scan_number_edit->setVisible(false);
  ui->msrun_auto_completion->setVisible(false);
  ui->mod_auto_completion->setVisible(false);
  ui->protein_search_edit->setVisible(true);

  connect(_project_window,
          &ProjectWindow::identificationGroupGrouped,
          this,
          &ProteinListWindow::doIdentificationGroupGrouped);

  connect(this,
          &ProteinListWindow::proteinDataChanged,
          _protein_table_model_p,
          &ProteinTableModel::onProteinDataChanged);
  connect(ui->tableView,
          &QTableView::clicked,
          _p_proxy_model,
          &ProteinTableProxyModel::onTableClicked);
  connect(_protein_table_model_p,
          &ProteinTableModel::layoutChanged,
          this,
          &ProteinListWindow::updateStatusBar);
  connect(_project_window,
          &ProjectWindow::projectNameChanged,
          this,
          &ProteinListWindow::doProjectNameChanged);
  connect(this,
          &ProteinListWindow::projectStatusChanged,
          _project_window,
          &ProjectWindow::doProjectStatusChanged);

  qDebug();
}

void
ProteinListWindow::doProxyLayoutChanged()
{
  // updateStatusBar();
  qDebug();
}

void
ProteinListWindow::askPeptideListView(ProteinMatch *p_protein_match)
{
  qDebug();
  _project_window->doViewPeptideList(_p_identification_group, p_protein_match);
  qDebug();
  // updateStatusBar();
}
void
ProteinListWindow::askProteinDetailView(ProteinMatch *p_protein_match)
{
  qDebug() << "ProteinListWindow::askProteinDetailView begin";
  _project_window->doViewProteinDetail(p_protein_match);
  qDebug() << "ProteinListWindow::askProteinDetailView end";
  // updateStatusBar();
}
void
ProteinListWindow::doFocusReceived(bool has_focus)
{
  if(has_focus)
    {
      qDebug() << "ProteinListWindow::doFocusReceived begin";
      _project_window->setDefaultProteinListWindow(this);
      qDebug() << "ProteinListWindow::doFocusReceived end";
    }
}

ProteinListWindow::~ProteinListWindow()
{
  // if (_p_ms_data_file != nullptr) delete _p_ms_data_file;
  delete ui;
  if(_p_context_menu != nullptr)
    {
      delete _p_context_menu;
    }
}

void
ProteinListWindow::edited()
{
  qDebug() << "ProteinListWindow::edited begin";
  // emit dataChanged(index, index);

  _project_window->doIdentificationGroupEdited(_p_identification_group);
  // updateStatusBar();
  emit projectStatusChanged();
  qDebug() << "ProteinListWindow::edited end";
}

void
ProteinListWindow::closeEvent(QCloseEvent *event)
{
  if(_p_context_menu != nullptr)
    {
      _p_context_menu->hide();
    }
  event->accept();
}

void
ProteinListWindow::doNotValidHide(bool hide)
{
  qDebug() << "ProteinListWindow::doNotValidHide begin";
  _p_proxy_model->hideNotValid(hide);
  QSettings settings;
  settings.setValue("proteinview/hidenotvalid", QString("%1").arg(hide));
  emit proteinDataChanged();
  emit projectStatusChanged();
  qDebug() << "ProteinListWindow::doNotValidHide end";
}

void
ProteinListWindow::doNotCheckedHide(bool hide)
{
  qDebug() << "ProteinListWindow::doNotCheckedHide begin";
  _p_proxy_model->hideNotChecked(hide);
  QSettings settings;
  settings.setValue("proteinview/hidenotchecked", QString("%1").arg(hide));
  emit proteinDataChanged();
  emit projectStatusChanged();
  qDebug() << "ProteinListWindow::doNotCheckedHide end";
}
void
ProteinListWindow::doNotGroupedHide(bool hide)
{
  qDebug() << "ProteinListWindow::doNotGroupedHide begin";
  _p_proxy_model->hideNotGrouped(hide);
  QSettings settings;
  settings.setValue("proteinview/hidenotgrouped", QString("%1").arg(hide));
  emit proteinDataChanged();
  emit projectStatusChanged();
  qDebug() << "ProteinListWindow::doNotGroupedHide end";
}

void
ProteinListWindow::doSearchOn(QString search_on)
{
  qDebug() << " begin " << search_on;
  _p_proxy_model->setSearchOn(search_on);
  ui->mod_auto_completion->setVisible(false);
  ui->scan_number_edit->setVisible(false);
  ui->msrun_auto_completion->setVisible(false);
  ui->protein_search_edit->setVisible(false);
  if(search_on == "MS run/scan")
    {

      qDebug() << " visible " << search_on;
      ui->scan_number_edit->setVisible(true);
      ui->msrun_auto_completion->setVisible(true);
    }
  else if(search_on == "Modifications")
    {

      qDebug() << " visible " << search_on;
      ui->mod_auto_completion->setVisible(true);
    }
  else
    {
      qDebug() << " hidden " << search_on;
      ui->protein_search_edit->setVisible(true);
    }

  emit proteinDataChanged();
}

void
ProteinListWindow::doMsrunFileSearch(QString msr_run_file_search
                                     [[maybe_unused]])
{
  //_p_proxy_model->setMsrunFileSearch(msr_run_file_search);
  emit proteinDataChanged();
}

void
ProteinListWindow::doModificationSearch(QString mod_search [[maybe_unused]])
{
  emit proteinDataChanged();
}
void
ProteinListWindow::doScanNumberSearch(int scan_num [[maybe_unused]])
{
  emit proteinDataChanged();
}

void
ProteinListWindow::onProteinSearchEdit(QString protein_search_string)
{
  qDebug() << "ProteinListWindow::onProteinSearchEdit begin "
           << protein_search_string;
  _p_proxy_model->setProteinSearchString(protein_search_string);
  emit proteinDataChanged();
}


void
ProteinListWindow::doIdentificationGroupGrouped(
  IdentificationGroup *p_identification_group)
{
  qDebug() << "ProteinListWindow::doIdentificationGroupGrouped begin";
  if(_p_identification_group == p_identification_group)
    {
      //_protein_table_model_p->setIdentificationGroup(p_identification_group);
      //_p_proxy_model->setSourceModel(_protein_table_model_p);
      emit proteinDataChanged();
    }

  qDebug() << "ProteinListWindow::doIdentificationGroupGrouped end";
}

void
ProteinListWindow::setIdentificationGroup(
  IdentificationGroup *p_identification_group)
{
  qDebug() << "ProteinListWindow::setIdentificationGroup begin ";
  if(p_identification_group != nullptr)
    {
      qDebug() << "ProteinListWindow::setIdentificationGroup not null";
      _p_identification_group = p_identification_group;
      _protein_table_model_p->setIdentificationGroup(p_identification_group);
      //_p_proxy_model->setSourceModel(_protein_table_model_p);

      if(_project_window->getProjectP()->getProjectMode() ==
         ProjectMode::individual)
        {
          this->setWindowTitle(QString("%1 protein list")
                                 .arg(_p_identification_group->getTabName()));
        }

      QStringList msrun_list;
      for(MsRunSp msrun_sp : _p_identification_group->getMsRunSpList())
        {
          msrun_list << msrun_sp.get()->getFileName();
          qDebug() << "ProteinListWindow::setIdentificationGroup "
                   << msrun_sp.get()->getFileName();
        }
      QCompleter *completer = new QCompleter(msrun_list, this);
      completer->setCaseSensitivity(Qt::CaseInsensitive);

      completer->setCompletionMode(QCompleter::PopupCompletion);
      completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
      completer->setFilterMode(Qt::MatchContains);
      ui->msrun_auto_completion->setCompleter(completer);


      QStringList mod_list;
      for(pappso::AaModificationP mod : _project_window->getProjectP()
                                          ->getPeptideStore()
                                          .getModificationCollection())
        {
          mod_list << QString("[%1] %2 %3")
                        .arg(mod->getAccession())
                        .arg(mod->getName())
                        .arg(mod->getMass());
          // qDebug() << "ProteinListWindow::setIdentificationGroup " <<
          // msrun_sp.get()->getFilename();
        }
      completer = new QCompleter(mod_list, this);
      completer->setCaseSensitivity(Qt::CaseInsensitive);

      completer->setCompletionMode(QCompleter::PopupCompletion);
      completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
      completer->setFilterMode(Qt::MatchContains);
      ui->mod_auto_completion->setCompleter(completer);

      _p_proxy_model->resteItemDelegates();
      setColumnMenuDisplay();
    }
  else
    {
      qDebug() << "ProteinListWindow::setIdentificationGroup  null";
    }

  qDebug() << "ProteinListWindow::setIdentificationGroup end";
}

void
ProteinListWindow::updateStatusBar()
{
  if(_p_identification_group == nullptr)
    {
    }
  else
    {
      ui->statusbar->showMessage(
        tr("proteins all:%1 valid:%2 valid&checked:%3 grouped:%4 displayed:%5")
          .arg(_p_identification_group->countProteinMatch(
            ValidationState::notValid))
          .arg(
            _p_identification_group->countProteinMatch(ValidationState::valid))
          .arg(_p_identification_group->countProteinMatch(
            ValidationState::validAndChecked))
          .arg(_p_identification_group->countProteinMatch(
            ValidationState::grouped))
          .arg(_p_proxy_model->rowCount()));
    }
}

void
ProteinListWindow::setProteinListColumnDisplay(ProteinListColumn column,
                                               bool toggled)
{
  _p_proxy_model->setProteinListColumnDisplay(column, toggled);
}
bool
ProteinListWindow::getProteinListColumnDisplay(ProteinListColumn column) const
{
  return _p_proxy_model->getProteinListColumnDisplay(column);
}
void
ProteinListWindow::resizeColumnsToContents()
{
  ui->tableView->resizeColumnsToContents();
}

ProjectWindow *
ProteinListWindow::getProjectWindow()
{
  return _project_window;
}


void
ProteinListWindow::doExportAsOdsFile()
{
  qDebug();
  QSettings settings;
  QString default_location = settings.value("path/export_ods", "").toString();

  QString filename;
  filename = QFileDialog::getSaveFileName(
    this,
    tr("Save ODS file"),
    QString("%1/untitled.ods").arg(default_location),
    tr("Open Document Spreadsheet (*.ods)"));

  if(!filename.isEmpty())
    {
      CalcWriterInterface *p_writer            = new OdsDocWriter(filename);
      const QAbstractProxyModel *p_table_model = _p_proxy_model;

      QtableWriter table_writer(p_writer, p_table_model);

      table_writer.setFormatPercentForColumn(
        _protein_table_model_p->index(0, (int)ProteinListColumn::coverage));

      table_writer.writeSheet("protein list");

      p_writer->close();
      delete p_writer;
    }
}

void
ProteinListWindow::doProjectNameChanged(QString name)
{
  setWindowTitle(tr("%1 - Protein list").arg(name));
}

void
ProteinListWindow::setColumnMenuDisplay()
{
  // Add the col name to the hide/show menu
  ui->menu_Columns->clear();
  ProteinListQactionColumn *p_action;
  for(int i = 0; i < _protein_table_model_p->columnCount(); i++)
    {
      p_action = new ProteinListQactionColumn(
        this, ProteinTableModel::getProteinListColumn(i));
      ui->menu_Columns->addAction(p_action);
    }
}
