//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================

#include "cumuluswidget.h"
#include "cumulusproxy.h"
#include "job.h"
#include "jobtablemodel.h"
#include "ui_cumuluswidget.h"

#include <QDesktopWidget>
#include <QList>
#include <QMessageBox>
#include <QNetworkReply>
#include <QTimer>

namespace
{
static constexpr int timer_period_msec = 10 * 1000;
}

namespace cumulus
{

CumulusWidget::CumulusWidget(QWidget* parentObject)
  : QWidget(parentObject)
  , m_ui(new Ui::CumulusWidget)
  , m_jobTableModel(new JobTableModel(this))
  , m_cumulusProxy(CumulusProxy::instance())
  , m_timer(nullptr)
  , m_loginDialog(this)
{
  m_ui->setupUi(this);

  this->createJobTable();

  connect(
    &m_loginDialog, &LoginDialog::entered, m_cumulusProxy.get(), &CumulusProxy::authenticateNewt);
  connect(
    m_cumulusProxy.get(),
    &CumulusProxy::authenticationFinished,
    this,
    &CumulusWidget::startJobFetchLoop);
  connect(
    m_cumulusProxy.get(), &CumulusProxy::jobsUpdated, m_jobTableModel, &JobTableModel::jobsUpdated);
  connect(m_cumulusProxy.get(), &CumulusProxy::error, this, &CumulusWidget::handleError);
  connect(
    m_cumulusProxy.get(),
    &CumulusProxy::newtAuthenticationError,
    this,
    &CumulusWidget::displayAuthError);
  connect(m_cumulusProxy.get(), &CumulusProxy::info, this, &CumulusWidget::info);
  connect(
    m_cumulusProxy.get(), &CumulusProxy::jobDownloaded, this, &CumulusWidget::handleDownloadResult);
  connect(
    m_jobTableModel,
    &JobTableModel::finishTimeChanged,
    m_cumulusProxy.get(),
    &CumulusProxy::patchJobs);

  // Relay newt session id from proxy
  connect(m_cumulusProxy.get(), &CumulusProxy::newtSessionId, this, &CumulusWidget::newtSessionId);

  // Instantiate polling timer (but don't start)
  m_timer = new QTimer(this);
  m_timer->setInterval(timer_period_msec);
  connect(m_timer, &QTimer::timeout, m_cumulusProxy.get(), &CumulusProxy::fetchJobs);
  m_ui->jobTableWidget->setEnabled(false);
}

CumulusWidget::~CumulusWidget()
{
  delete m_ui;
}

void CumulusWidget::girderUrl(const QString& url)
{
  m_cumulusProxy->girderUrl(url);
}

bool CumulusWidget::isGirderRunning() const
{
  return m_cumulusProxy->isGirderRunning();
}

void CumulusWidget::showLoginDialog()
{
  m_loginDialog.show();
}

void CumulusWidget::addContextMenuAction(const QString& status, QAction* action)
{
  m_ui->jobTableWidget->addContextMenuAction(status, action);
}

void CumulusWidget::authenticateGirder(const QString& newtSessionId)
{
  m_cumulusProxy->authenticateGirder(newtSessionId);
}

void CumulusWidget::startPolling()
{
  m_timer->start();
}

void CumulusWidget::stopPolling()
{
  m_timer->stop();
}

void CumulusWidget::createJobTable()
{
  m_ui->jobTableWidget->setModel(m_jobTableModel);
  m_ui->jobTableWidget->setCumulusProxy(m_cumulusProxy);
}

void CumulusWidget::startJobFetchLoop()
{
  m_ui->jobTableWidget->setEnabled(true);
  m_cumulusProxy->fetchJobs();
  m_timer->start();
}

void CumulusWidget::displayAuthError(const QString& msg)
{
  m_loginDialog.setErrorMessage(msg);
  m_loginDialog.show();
}

void CumulusWidget::handleError(const QString& msg, QNetworkReply* networkReply)
{
  if (networkReply)
  {
    int statusCode = networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).value<int>();

    // Forbidden, ask the user to authenticate again
    if (statusCode == 403)
    {
      m_timer->stop();
      m_ui->jobTableWidget->setEnabled(false);
      QMessageBox::warning(this, "Access Denied", "Access was denied (Http 403).");
      return;
    }
    else if (networkReply->error() == QNetworkReply::ConnectionRefusedError)
    {
      m_timer->stop();
      m_ui->jobTableWidget->setEnabled(false);
      QMessageBox::critical(
        nullptr,
        QObject::tr("Connection refused"),
        QObject::tr("Unable to connect to server at %1:%2, please ensure server is running.")
          .arg(networkReply->url().host())
          .arg(networkReply->url().port()));
      m_loginDialog.show();
    }
    else
    {
      QMessageBox::critical(this, "", msg, QMessageBox::Ok);
    }
  }
  else
  {
    QMessageBox::critical(this, "", msg, QMessageBox::Ok);
  }
}

void CumulusWidget::handleDownloadResult(const cumulus::Job& job, const QString& path)
{
  (void)job;
  emit this->resultDownloaded(path);
}

} // namespace cumulus
