
/*******************************************************************************
 * Copyright (c) 2019 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:
 *    Thomas Renne <thomas.renne@u-psud.fr>. - initial API and
 *implementation
 ******************************************************************************/

#include "ui_ms_identification_run_view.h"
#include "msidentificationlistwindow.h"

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

MsIdentificationListQActionColumn::MsIdentificationListQActionColumn(
  MsIdentificationListWindow *parent, msIdentificationListColumn column)
  : QAction(parent)
{

  this->setText(MsIdentificationTableModel::getTitle(
    MsIdentificationTableModel::getColumnIndex(column)));

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

  m_column           = column;
  m_msid_list_window = parent;

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

MsIdentificationListQActionColumn::~MsIdentificationListQActionColumn()
{
  // if (_p_ms_data_file != nullptr) delete _p_ms_data_file;
  qDebug() << "begin ";
}
void
MsIdentificationListQActionColumn::doToggled(bool toggled)
{
  qDebug() << "begin " << toggled;
  setChecked(toggled);
  m_msid_list_window->setMsIdentificationListColumnDisplay(m_column, toggled);

  qDebug() << "end";
}


MsIdentificationListWindow::MsIdentificationListWindow(ProjectWindow *parent)
  : QMainWindow(parent), ui(new Ui::MsIdentificationView)
{
  qDebug();
  mp_projectWindow = parent;
  ui->setupUi(this);
  setWindowIcon(QIcon(":/i2masschroq_icon/resources/i2MassChroQ_icon.svg"));

  // Set Window title based on project name
  if(mp_projectWindow->getProjectP() != nullptr)
    {
      setWindowTitle(QString("%1 - Ms Identification list")
                       .arg(mp_projectWindow->getProjectP()->getProjectName()));
    }

  qDebug();
  // Configure the dynamic table
  mp_msidTableModel =
    new MsIdentificationTableModel(this, mp_projectWindow->getProjectP());

  mp_proxyModel = new MsIdentificationTableProxyModel(this, mp_msidTableModel);
  mp_proxyModel->setSourceModel(mp_msidTableModel);
  mp_proxyModel->setDynamicSortFilter(true);

  qDebug();
  ui->tableView->setModel(mp_proxyModel);
  ui->tableView->setSortingEnabled(true);
  ui->tableView->horizontalHeader()->setSectionsMovable(true);

  qDebug();
  // Add the col name to the hide/show menu
  MsIdentificationListQActionColumn *p_action;
  for(int i = 0; i < mp_msidTableModel->columnCount(); i++)
    {
      p_action = new MsIdentificationListQActionColumn(
        this, MsIdentificationTableModel::getMsIdentificationListColumn(i));
      ui->menuColumns->addAction(p_action);
    }

  // Create the copying path menu
  mp_copyPathMenu = new QMenu();

  qDebug();
  // Handle signals/slots
  connect(this,
          &MsIdentificationListWindow::MsIdentificationDataChanged,
          mp_msidTableModel,
          &MsIdentificationTableModel::onMsIdentificationDataChanged);
  connect(mp_msidTableModel,
          &MsIdentificationTableModel::layoutChanged,
          this,
          &MsIdentificationListWindow::updateStatusBar);
  connect(ui->tableView,
          &QWidget::customContextMenuRequested,
          this,
          &MsIdentificationListWindow::showGroupsContextMenu);
  connect(ui->tableView,
          &QTableView::clicked,
          mp_proxyModel,
          &MsIdentificationTableProxyModel::onTableClicked);
  connect(ui->tableView->verticalScrollBar(),
          &QScrollBar::valueChanged,
          mp_msidTableModel,
          &MsIdentificationTableModel::changeWaitingQueue);
  connect(mp_projectWindow,
          &ProjectWindow::projectNameChanged,
          this,
          &MsIdentificationListWindow::doProjectNameChanged);
  connect(mp_msidTableModel,
          &MsIdentificationTableModel::projectStatusChanged,
          mp_projectWindow,
          &ProjectWindow::doProjectStatusChanged);
  connect(ui->actionExport,
          &QAction::triggered,
          mp_projectWindow,
          &ProjectWindow::doOpenMassChroQDialog);
  connect(mp_copyPathMenu,
          &QMenu::triggered,
          this,
          &MsIdentificationListWindow::doCopyPath);
}


MsIdentificationListWindow::~MsIdentificationListWindow()
{
  qDebug();
  delete ui;
  if(mp_groups_context_menu != nullptr)
    {
      delete mp_groups_context_menu;
    }
}

void
MsIdentificationListWindow::closeEvent(QCloseEvent *event)
{
  qDebug();
  mp_msidTableModel->stopThreads();
  if(mp_groups_context_menu != nullptr)
    {
      mp_groups_context_menu->hide();
    }
  event->accept();
}

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

void
MsIdentificationListWindow::doSearchOn(QString search_on)
{
  qDebug() << "ProteinTableProxyModel::doSearchOn begin " << search_on;
  mp_proxyModel->setSearchOn(search_on);
  emit MsIdentificationDataChanged();
}

void
MsIdentificationListWindow::onMsIdentificationSearchEdit(
  QString ms_id_search_string)
{
  qDebug()
    << "MsIdentificationTableProxyModel::onMsIdentificationSearchEdit begin "
    << ms_id_search_string;
  mp_proxyModel->setMsIdentificationSearchString(ms_id_search_string);
  emit MsIdentificationDataChanged();
}

void
MsIdentificationListWindow::showGroupsContextMenu(const QPoint &pos)
{
  QModelIndex corrected_index =
    mp_proxyModel->mapToSource(ui->tableView->indexAt(pos));

  qDebug() << "check the column" << corrected_index.column();
  // Handle Alignement Groups
  if(corrected_index.column() ==
     (std::int8_t)msIdentificationListColumn::align_groups)
    {
      if(mp_groups_context_menu == nullptr)
        {
          mp_groups_context_menu =
            new AlignmentGroupsQMenu(this, mp_projectWindow->getProjectP());
          mp_groups_context_menu->exec(QCursor::pos());
        }
      else
        {
          mp_groups_context_menu->exec(QCursor::pos());
        }
    }

  // Handle the file path copy to clipboard
  if(corrected_index.column() ==
       (std::int8_t)msIdentificationListColumn::id_file ||
     corrected_index.column() == (std::int8_t)msIdentificationListColumn::mzML)
    {
      mp_copyPathMenu->clear();
      QAction *copy_action =
        new QAction(QIcon::fromTheme("edit-copy"), "copy path");
      mp_copyPathMenu->addAction(copy_action);
      m_askIndex = corrected_index;
      mp_copyPathMenu->exec(QCursor::pos());
    }

  // Handle multiple path copy to clipboard
  if(corrected_index.column() ==
     (std::int8_t)msIdentificationListColumn::fasta_file)
    {
      mp_copyPathMenu->clear();
      QMenu *copy_menu = new QMenu("copy path");
      copy_menu->setIcon(QIcon::fromTheme("edit-copy"));
      std::vector<FastaFileSp> fasta_list =
        mp_msidTableModel->getIdentificationDataSourceSpList()
          .at(corrected_index.row())
          ->getFastaFileList();

      for(FastaFileSp fasta_file : fasta_list)
        {
          copy_menu->addAction(QString("%1").arg(fasta_file->getFilename()));
        }
      mp_copyPathMenu->addMenu(copy_menu);

      m_askIndex = corrected_index;
      mp_copyPathMenu->exec(QCursor::pos());
    }
}

void
MsIdentificationListWindow::doCopyPath(QAction *action)
{
  QString path;
  if(action->text() == "copy path")
    {

      if(m_askIndex.column() ==
         (std::int8_t)msIdentificationListColumn::id_file)
        {
          path = mp_msidTableModel->getIdentificationDataSourceSpList()
                   .at(m_askIndex.row())
                   ->getResourceName();
        }
      if(m_askIndex.column() == (std::int8_t)msIdentificationListColumn::mzML)
        {
          path = mp_msidTableModel->getIdentificationDataSourceSpList()
                   .at(m_askIndex.row())
                   ->getMsRunSp()
                   ->getFileName();
        }
    }
  else // fasta file path asked to be copied
    {
      std::vector<FastaFileSp> fasta_list =
        mp_msidTableModel->getIdentificationDataSourceSpList()
          .at(m_askIndex.row())
          ->getFastaFileList();
      for(FastaFileSp fasta_file : fasta_list)
        {
          if(fasta_file->getFilename() == action->text())
            {
              path = fasta_file->getAbsoluteFilePath();
            }
        }
    }
  qDebug() << path << "copied";
  QClipboard *clipboard = QGuiApplication::clipboard();
  clipboard->setText(path);
  qDebug();
}

void
MsIdentificationListWindow::updateStatusBar()
{
  qDebug();
  ui->statusbar->showMessage(
    tr("Ms identification all:%1 displayed:%5")
      .arg(mp_msidTableModel->getIdentificationDataSourceSpList().size())
      .arg(mp_proxyModel->rowCount()));
  qDebug();
}

void
MsIdentificationListWindow::setIdentificationDataSourceSpList(
  std::vector<IdentificationDataSourceSp> &identificationDataSourceSpList)
{
  qDebug();

  mp_msidTableModel->setIdentificationDataSourceSpList(
    identificationDataSourceSpList);
  mp_proxyModel->resteItemDelegates();
  qDebug();
}

std::vector<IdentificationDataSourceSp>
MsIdentificationListWindow::getIdentificationDataSourceSpList()
{
  qDebug();
  return mp_msidTableModel->getIdentificationDataSourceSpList();
}


void
MsIdentificationListWindow::doExportAsOdsFile()
{
  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 = mp_proxyModel;

      QtableWriter table_writer(p_writer, p_table_model);

      table_writer.setFormatPercentForColumn(mp_msidTableModel->index(
        0, (int)msIdentificationListColumn::percent_assign));
      table_writer.setFormatPercentForColumn(mp_msidTableModel->index(
        0, (int)msIdentificationListColumn::msrun_percent_assign));

      table_writer.writeSheet("Ms Identification list");

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

void
MsIdentificationListWindow::setMsIdentificationListColumnDisplay(
  msIdentificationListColumn column, bool toggled)
{
  mp_proxyModel->setMsIdentificationListColumnDisplay(column, toggled);
}

bool
MsIdentificationListWindow::getMsIdentificationListColumnDisplay(
  msIdentificationListColumn column) const
{
  return mp_proxyModel->getMsIdentificationListColumnDisplay(column);
}

void
MsIdentificationListWindow::askEngineDetailView(
  IdentificationDataSourceSp *identificationEngine)
{
  qDebug() << "begin";
  mp_projectWindow->doViewEngineDetail(identificationEngine);
  qDebug() << "end";
}

void
MsIdentificationListWindow::doProjectNameChanged(QString name)
{
  setWindowTitle(tr("%1 - Ms Identification list").arg(name));
}

void
MsIdentificationListWindow::setAlignmentGroup(
  MsRunAlignmentGroupSp msrun_alignment_group)
{
  foreach(QModelIndex index, getSelectedIndexes())
    {
      int position = mp_proxyModel->mapToSource(index).row();

      MsRunSp ms_run = mp_msidTableModel->getIdentificationDataSourceSpList()
                         .at(position)
                         ->getMsRunSp();

      if(msrun_alignment_group != nullptr)
        {
          msrun_alignment_group.get()->addMsRunToMsRunAlignmentGroupList(
            ms_run);

          mp_proxyModel->setData(
            index,
            msrun_alignment_group->getMsRunAlignmentGroupName(),
            Qt::EditRole);
        }
      else
        {
          ms_run.get()
            ->getAlignmentGroup()
            ->removeMsRunFromMsRunAlignmentGroupList(ms_run);

          mp_proxyModel->setData(index, QVariant(), Qt::EditRole);
        }
    }
}

QModelIndexList
MsIdentificationListWindow::getSelectedIndexes()
{
  return ui->tableView->selectionModel()->selectedIndexes();
}

void
MsIdentificationListWindow::doMassChroQParameters()
{
  emit operateMassChroqExportDialog();
}

MsIdentificationTableProxyModel *
MsIdentificationListWindow::getMsIdentificationProxyModel()
{
  return mp_proxyModel;
}

MsIdentificationTableModel *
MsIdentificationListWindow::getMsIdentificationModel()
{
  return mp_msidTableModel;
}

void
MsIdentificationListWindow::doValidPeptideEvidenceInProjectChanged()
{
  // TODO there is a new selection, we need to compute number of spectra
  // assigned
}
