
/*******************************************************************************
 * 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 <QSettings>
#include <odsstream/odsdocwriter.h>
#include <odsstream/qtablewriter.h>
#include "peptidelistwindow.h"
#include "../project_view/projectwindow.h"

#include "ui_peptide_view.h"

PeptideListQactionColumn::PeptideListQactionColumn(PeptideListWindow *parent,
                                                   PeptideListColumn column)
  : QAction(parent)
{

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

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


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

#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(this,
          &PeptideListQactionColumn::toggled,
          this,
          &PeptideListQactionColumn::doToggled);
#else
  // Qt4 code
  connect(this, SIGNAL(toggled(bool)), this, SLOT(doToggled(bool)));
#endif
}

PeptideListQactionColumn::~PeptideListQactionColumn()
{
  // if (_p_ms_data_file != nullptr) delete _p_ms_data_file;
  qDebug() << "PeptideListQactionColumn::~PeptideListQactionColumn begin ";
}

void
PeptideListQactionColumn::doToggled(bool toggled)
{
  qDebug() << "PeptideListQactionColumn::doToggled begin " << toggled;
  setChecked(toggled);
  _p_peptide_list_window->setPeptideListColumnDisplay(_column, toggled);

  qDebug() << "PeptideListQactionColumn::doToggled end";
}


PeptideListWindow::PeptideListWindow(ProjectWindow *parent)
  : QMainWindow(parent), ui(new Ui::PeptideView)
{
  _project_window = parent;
  ui->setupUi(this);

  _peptide_table_model_p = new PeptideTableModel(this);

  if(_project_window->getProjectP() != nullptr)
    {
      setWindowTitle(QString("%1 - Peptide list")
                       .arg(_project_window->getProjectP()->getProjectName()));
    }

  _p_proxy_model = new PeptideTableProxyModel(this, _peptide_table_model_p);
  _p_proxy_model->setSourceModel(_peptide_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);

  // connect(ui->tableView, SIGNAL(clicked(const QModelIndex &)),
  // _p_proxy_model, SLOT(onTableClicked(const QModelIndex &)));


  QSettings settings;
  bool hide = settings.value("peptideview/hidenotvalid", "true").toBool();
  ui->actionValid_peptides->setChecked(hide);
  _p_proxy_model->hideNotValid(hide);
  hide = settings.value("peptideview/hidenotchecked", "false").toBool();
  ui->actionChecked_peptides->setChecked(hide);
  _p_proxy_model->hideNotChecked(hide);
  hide = settings.value("peptideview/hidenotgrouped", "false").toBool();

  ui->actionGrouped_peptides->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->peptide_search_edit->setVisible(true);

#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(_project_window,
          &ProjectWindow::identificationGroupGrouped,
          this,
          &PeptideListWindow::doIdentificationGroupGrouped);

  connect(this,
          &PeptideListWindow::peptideDataChanged,
          _peptide_table_model_p,
          &PeptideTableModel::onPeptideDataChanged);

  connect(ui->tableView,
          &QTableView::clicked,
          _p_proxy_model,
          &PeptideTableProxyModel::onTableClicked);
  connect(_peptide_table_model_p,
          &PeptideTableModel::layoutChanged,
          this,
          &PeptideListWindow::updateStatusBar);
  connect(ui->centralwidget,
          &QWidget::customContextMenuRequested,
          this,
          &PeptideListWindow::showContextMenu);
  connect(_project_window,
          &ProjectWindow::projectNameChanged,
          this,
          &PeptideListWindow::doProjectNameChanged);
#else
  // Qt4 code
  connect(_project_window,
          SIGNAL(identificationGroupGrouped(IdentificationGroup *)),
          this,
          SLOT(doIdentificationGroupGrouped(IdentificationGroup *)));

  connect(this,
          SIGNAL(peptideDataChanged()),
          _peptide_table_model_p,
          SLOT(onPeptideDataChanged()));

  connect(ui->tableView,
          SIGNAL(clicked(const QModelIndex &)),
          _p_proxy_model,
          SLOT(onTableClicked(const QModelIndex &)));
  connect(_peptide_table_model_p,
          SIGNAL(layoutChanged()),
          this,
          SLOT(updateStatusBar()));

  /*
      connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
      connect(this, SIGNAL(operateMsDataFile(QString)),
     worker,SLOT(doMsDataFileLoad(QString))); connect(worker,
     SIGNAL(msDataReady(pwiz::msdata::MSDataFile *)), this,
     SLOT(handleMsDataFile(pwiz::msdata::MSDataFile *)));
      */
#endif
  /*
   */
}

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

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

void
PeptideListWindow::doIdentificationGroupGrouped(
  IdentificationGroup *p_identification_group [[maybe_unused]])
{
}
ProjectWindow *
PeptideListWindow::getProjectWindow()
{
  return _project_window;
}
void
PeptideListWindow::setProteinMatch(IdentificationGroup *p_identification_group,
                                   ProteinMatch *p_protein_match)
{
  if(_p_protein_match != p_protein_match)
    {
      _p_identification_group = p_identification_group;
      _p_protein_match        = p_protein_match;
      _peptide_table_model_p->setProteinMatch(p_protein_match);
      //_p_proxy_model->setSourceModel(_peptide_table_model_p);
      ui->description_label->setText(
        p_protein_match->getProteinXtpSp().get()->getDescription());
      ui->accession_label->setText(
        p_protein_match->getProteinXtpSp().get()->getAccession());
      updateStatusBar();


      QStringList msrun_list;
      for(MsRunSp msrun_sp : _p_identification_group->getMsRunSpList())
        {
          msrun_list << msrun_sp.get()->getFileName();
          qDebug() << "PeptideListWindow::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->sort((std::int8_t)PeptideListColumn::peptide_grouping_id,
                           Qt::AscendingOrder);


      _p_proxy_model->resteItemDelegates();
    }
}


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

  _p_protein_match->updateAutomaticFilters(
    _project_window->getProjectP()->getAutomaticFilterParameters());
  _project_window->doIdentificationGroupEdited(_p_identification_group);
  // updateStatusBar();

  qDebug() << "PeptideListWindow::edited end";
}
void
PeptideListWindow::doNotValidHide(bool hide)
{
  qDebug() << "PeptideListWindow::doNotValidHide begin";
  _p_proxy_model->hideNotValid(hide);
  QSettings settings;
  settings.setValue("peptidelistview/hidenotvalid", QString("%1").arg(hide));
  emit peptideDataChanged();
  qDebug() << "PeptideListWindow::doNotValidHide end";
}

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


void
PeptideListWindow::askPeptideDetailView(PeptideEvidence *p_peptide_evidence)
{
  qDebug() << "PeptideListWindow::askPeptideDetailView begin";
  _project_window->doViewPeptideDetail(p_peptide_evidence);
  qDebug() << "PeptideListWindow::askPeptideDetailView end";
  // updateStatusBar();
}

void
PeptideListWindow::doPeptideSearchEdit(QString protein_search_string)
{
  qDebug() << "PeptideListWindow::onProteinSearchEdit begin "
           << protein_search_string;
  _p_proxy_model->setPeptideSearchString(protein_search_string);
  emit peptideDataChanged();
}

void
PeptideListWindow::doModificationSearch(QString mod_search [[maybe_unused]])
{
  //_p_proxy_model->setMsrunFileSearch(msr_run_file_search);
  emit peptideDataChanged();
}
void
PeptideListWindow::doMsrunFileSearch(QString msr_run_file_search)
{
  qDebug() << "PeptideListWindow::doMsrunFileSearch begin "
           << msr_run_file_search;
  emit peptideDataChanged();
}
void
PeptideListWindow::doScanNumberSearch(int scan_num)
{
  qDebug() << "PeptideListWindow::doScanNumberSearch begin " << scan_num;
  emit peptideDataChanged();
}
void
PeptideListWindow::doSearchOn(QString search_on)
{
  qDebug() << "PeptideListWindow::doSearchOn begin " << search_on;
  _p_proxy_model->setSearchOn(search_on);

  ui->scan_number_edit->setVisible(false);
  ui->msrun_auto_completion->setVisible(false);
  ui->peptide_search_edit->setVisible(false);
  ui->mod_auto_completion->setVisible(false);
  if(search_on == "msrun/scan")
    {

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

      qDebug() << "PeptideListWindow::doSearchOn visible " << search_on;
      ui->mod_auto_completion->setVisible(true);
    }
  else
    {
      qDebug() << "PeptideListWindow::doSearchOn hidden " << search_on;
      ui->peptide_search_edit->setVisible(true);
    }
  // emit proteinDataChanged();
  emit peptideDataChanged();
}

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

void
PeptideListWindow::resizeColumnsToContents()
{
  ui->tableView->resizeColumnsToContents();
}


void
PeptideListWindow::showContextMenu(const QPoint &pos)
{
  if(_p_context_menu == nullptr)
    {
      _p_context_menu = new QMenu(tr("Context menu"), this);


      PeptideListQactionColumn *p_action;
      for(std::int8_t i = 0; i < _peptide_table_model_p->columnCount(); i++)
        {
          p_action = new PeptideListQactionColumn(
            this, PeptideTableModel::getPeptideListColumn(i));
          _p_context_menu->addAction(p_action);
        }

      _p_context_menu->exec(mapToGlobal(pos));
    }
  else
    {
      _p_context_menu->move(mapToGlobal(pos));
      _p_context_menu->show();
    }
}


void
PeptideListWindow::setPeptideListColumnDisplay(PeptideListColumn column,
                                               bool toggled)
{
  _p_proxy_model->setPeptideListColumnDisplay(column, toggled);
}
/*
void PeptideListWindow::resizeColumnsToContents() {
    ui->tableView->resizeColumnsToContents();
}
*/

bool
PeptideListWindow::getPeptideListColumnDisplay(PeptideListColumn column) const
{
  return _p_proxy_model->getPeptideListColumnDisplay(column);
}

void
PeptideListWindow::doExportAsOdsFile()
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
  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);
      p_writer->writeSheet("protein");
      p_writer->writeCell("accession");
      p_writer->writeCell(
        _p_protein_match->getProteinXtpSp().get()->getAccession());
      p_writer->writeLine();
      p_writer->writeCell("description");
      p_writer->writeCell(
        _p_protein_match->getProteinXtpSp().get()->getDescription());
      p_writer->writeLine();
      p_writer->writeCell("sequence");
      p_writer->writeCell(
        _p_protein_match->getProteinXtpSp().get()->getSequence());
      p_writer->writeLine();


      const QAbstractProxyModel *p_table_model = _p_proxy_model;

      QtableWriter table_writer(p_writer, p_table_model);

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

      table_writer.writeSheet("peptide list");

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

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