
/*******************************************************************************
 * 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 "proteinwindow.h"
#include "../project_view/projectwindow.h"
#include "ui_protein_detail_view.h"
#include "../../core/proteinmatch.h"
#include <pappsomspp/pappsoexception.h>
#include <QMessageBox>
#include <QDesktopServices>
#include <QSvgGenerator>
#include <cmath>
//#include <QWebEnginePage>
//#include <QtWebEngine>

DbXrefButton::DbXrefButton(QWidget *parent, DbXref dbxref) : QPushButton(parent)
{
  _dbxref = dbxref;
#if QT_VERSION >= 0x050000
  // Qt5 code
  QObject::connect(
    this, &DbXrefButton::clicked, this, &DbXrefButton::clickedSlot);
#else
  // Qt4 code
  QObject::connect(this, SIGNAL(clicked()), this, SLOT(clickedSlot()));
#endif

  setText(_dbxref.accession);
}

void
DbXrefButton::clickedSlot()
{
  qDebug() << "DbXrefButton::clickedSlot " << _dbxref.getUrl();
  QDesktopServices::openUrl(_dbxref.getUrl());
}

ProteinWindow::ProteinWindow(ProjectWindow *parent)
  : QMainWindow(parent), ui(new Ui::ProteinDetailView)
{
  _p_project_window = parent;
  ui->setupUi(this);
  /*
   */
  if(_p_project_window->getProjectP() != nullptr)
    {
      setWindowTitle(
        QString("%1 - Protein details")
          .arg(_p_project_window->getProjectP()->getProjectName()));
    }

#if QT_VERSION >= 0x050000
  // Qt5 code
  connect(_p_project_window,
          &ProjectWindow::identificationGroupGrouped,
          this,
          &ProteinWindow::doIdentificationGroupGrouped);
  connect(_p_project_window,
          &ProjectWindow::peptideEvidenceSelected,
          this,
          &ProteinWindow::doPeptideEvidenceSelected);
  connect(_p_project_window,
          &ProjectWindow::projectNameChanged,
          this,
          &ProteinWindow::doProjectNameChanged);
#else
  // Qt4 code
  connect(_p_project_window,
          SIGNAL(identificationGroupGrouped(IdentificationGroup *)),
          this,
          SLOT(doIdentificationGroupGrouped(IdentificationGroup *)));
  connect(_p_project_window,
          SIGNAL(peptideMatchSelected(PeptideMatch *)),
          this,
          SLOT(doPeptideMatchSelected(PeptideMatch *)));

  // connect(_protein_table_model_p, SIGNAL(layoutChanged()), this,
  // SLOT(updateStatusBar()));
#endif
}

ProteinWindow::~ProteinWindow()
{
  clearDbXrefLayout();
  delete ui;
}
void
ProteinWindow::doIdentificationGroupGrouped(
  IdentificationGroup *p_identification_group [[maybe_unused]])
{
  updateDisplay();
}

void
ProteinWindow::doPeptideEvidenceSelected(PeptideEvidence *peptide_evidence)
{
  if(peptide_evidence != nullptr)
    {
      ui->sequenceTextEdit->setText(
        _p_protein_match->getHtmlSequence(peptide_evidence));
    }
}
void
ProteinWindow::clearDbXrefLayout()
{
  for(int i = 0; i < ui->dbxref_list_layout->count(); ++i)
    {
      delete ui->dbxref_list_layout->itemAt(i)->widget();
    }
}
void
ProteinWindow::browseUrl(int i [[maybe_unused]])
{
}
void
ProteinWindow::updateDisplay()
{
  try
    {
      clearDbXrefLayout();
      // valid protein
      ui->valid_checkbox->setCheckState(Qt::Unchecked);
      if(_p_protein_match->isValid())
        ui->valid_checkbox->setCheckState(Qt::Checked);

      // contaminant protein
      ui->contaminant_checkbox->setCheckState(Qt::Unchecked);
      if(_p_protein_match->getProteinXtpSp().get()->isContaminant())
        ui->contaminant_checkbox->setCheckState(Qt::Checked);

      // decoy protein (reversed)
      ui->decoy_checkbox->setCheckState(Qt::Unchecked);
      if(_p_protein_match->getProteinXtpSp().get()->isDecoy())
        ui->decoy_checkbox->setCheckState(Qt::Checked);
      ui->accession_label->setText(
        _p_protein_match->getProteinXtpSp().get()->getAccession());
      for(const DbXref &dbxref :
          _p_protein_match->getProteinXtpSp().get()->getDbxrefList())
        {
          QString accession = ui->accession_label->text().replace(
            dbxref.accession,
            QString("<span style=\"color:%2;\">%1</span>")
              .arg(dbxref.accession)
              .arg("blue"));
          ui->accession_label->setText(accession);
          qDebug() << "ProteinWindow::updateDisplay " << accession;

          DbXrefButton *dbxref_button = new DbXrefButton(this, dbxref);
          ui->dbxref_list_layout->addWidget(dbxref_button);
        }

      ui->button_layout->setVisible(true);
      if(ui->dbxref_list_layout->count() == 0)
        {
          ui->button_layout->setVisible(false);
        }
      ui->description_label->setText(
        _p_protein_match->getProteinXtpSp().get()->getDescription());
      ui->sequenceTextEdit->setText(_p_protein_match->getHtmlSequence());
      ui->coverage_label->setText(
        QString("%1 %").arg(_p_protein_match->getCoverage() * 100));
      ui->mw_label->setText(QString("%1 kDa").arg(
        _p_protein_match->getProteinXtpSp().get()->getMass() / 1000));
      ui->evalue_label->setText(QString("%1 (log10: %2)")
                                  .arg(_p_protein_match->getEvalue())
                                  .arg(_p_protein_match->getLogEvalue()));
    }
  catch(pappso::PappsoException &exception_pappso)
    {
      QMessageBox::warning(this,
                           tr("Unable to display protein details :"),
                           exception_pappso.qwhat());
    }
  catch(std::exception &exception_std)
    {
      QMessageBox::warning(
        this, tr("Unable to display protein details :"), exception_std.what());
    }
}

void
ProteinWindow::setProteinMatch(ProteinMatch *p_protein_match)
{
  _p_protein_match = p_protein_match;
  updateDisplay();
}

void
ProteinWindow::doSaveSvg()
{

  try
    {
      QSettings settings;
      QString default_location =
        settings.value("path/export_svg", "").toString();

      QString proposed_filename =
        QString("%1/protein_%1.pdf")
          .arg(_p_protein_match->getProteinXtpSp().get()->getAccession());

      QString filename = QFileDialog::getSaveFileName(
        this, tr("Save PDF file"), proposed_filename, tr("pdf (*.pdf)"));

      if(filename.isEmpty())
        {
          return;
        }

      settings.setValue("path/export_svg", QFileInfo(filename).absolutePath());

      // https://bugreports.qt.io/browse/QTBUG-52538
      QPrinter printer(QPrinter::PrinterResolution);
      printer.setOutputFormat(QPrinter::PdfFormat);
      printer.setPaperSize(QPrinter::A4);
      printer.setOutputFileName(filename);
      /*
          QSvgGenerator generator;
          //generator.setOutputDevice(&buffer);
          QSize size(600, 1000);
          generator.setFileName(filename);
          generator.setSize(size);
          generator.setViewBox(QRect(0, 0, size.width(), size.height()));
          generator.setTitle(_p_protein_match->getProteinXtpSp().get()->getAccession());
          */

      // generator.setDescription(description);
      // QPainter painter;
      // painter.begin(&generator);
      // painter.setViewport(0,0, size.width(), size.height());

      // ui->sequenceTextEdit->document()->drawContents(&painter);
      // painter.end();
      // QFont::Monospace
      QFont font("Monospace");
      font.setStyleHint(QFont::Monospace);
      font.setLetterSpacing(QFont::AbsoluteSpacing, 0);
      font.setPointSize(10); // generator.setDefaultFont(font);

      QTextOption text_option;
      text_option.setWrapMode(QTextOption::WrapAnywhere);
      text_option.setFlags(QTextOption::IncludeTrailingSpaces |
                           QTextOption::ShowTabsAndSpaces);
      text_option.setUseDesignMetrics(0);

      // QTextDocument *doc = ui->sequenceTextEdit->document()->clone();
      QTextDocument *doc = new QTextDocument();
      doc->setHtml(QString("<p>%1</p><p>%2</p><p>%3</p>")
                     .arg(_p_protein_match->getProteinXtpSp()
                            .get()
                            ->getAccession()
                            .toHtmlEscaped())
                     .arg(_p_protein_match->getProteinXtpSp()
                            .get()
                            ->getDescription()
                            .toHtmlEscaped())
                     .arg(ui->sequenceTextEdit->toHtml()));
      doc->setUndoRedoEnabled(false);
      // doc->setHtml("<p><span style=\"color:#000000;
      // font-weight:600\">"+text_x+"</span></p>");
      doc->setTextWidth(printer.pageRect().size().width());
      doc->setDefaultFont(font);
      doc->setPageSize(printer.pageRect().size());
      //// height from doc QTextDocument
      ////
      /// http://fop-miniscribus.googlecode.com/svn/trunk/fop_miniscribus.1.0.0/src/floating_box/floatdiagram.cpp
      //////setMaximumHeight(DocumentHighgtActual());
      doc->setPageSize(
        printer.pageRect()
          .size()); // This is necessary if you want to hide the page number
      doc->print(&printer);

      /*
          QPainter *painter = new QPainter(&generator);
          painter->setRenderHint(QPainter::Antialiasing, true);
          painter->setFont(font);
          doc->drawContents(painter);
          painter->end();
          */


      /*
              QSvgGenerator svg;
      svg.setFileName(filename);
      QTextDocument *doc = ui->sequenceTextEdit->document()->clone();
      QRect rectSize(0, 0, (int) doc->size().width(), (int)
      doc->size().height()); QPainter painter(&svg);
      //painter.setViewport(rectSize);
      //doc->documentLayout()->setPaintDevice(&svg);
      doc->drawContents(&painter);
      */

      /*
      QtWebEngine::initialize();
          QWebEnginePage page;
          QEventLoop loop;
          loop.connect(&page, &QWebEnginePage::loadFinished, [&page, &loop,
      &filename]() { page.printToPdf([&loop, &filename] (QByteArray ba) { QFile
      f(filename); if (f.open(QIODevice::WriteOnly))
                  {
                      f.write(ba);
                      f.close();
                  } else {
                      qDebug() << "Error opening file for writing" << filename
      << f.errorString();
                  }
                  loop.exit();
              });
          });
          qDebug() << ui->sequenceTextEdit->toHtml();
          page.setHtml(ui->sequenceTextEdit->toHtml());
          loop.exec();
          */
    }
  catch(pappso::PappsoException &error)
    {
      QMessageBox::warning(
        this, tr("Error trying to save spectrum to SVG file :"), error.qwhat());
    }
}

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