/**********************************************************************************************
    Copyright (C) 2014-2015 Oliver Eichler <oliver.eichler@gmx.de>

    This program 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.

    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************************/

#include "helpers/CProgressDialog.h"

#include <QtWidgets>

#include "CMainWindow.h"
#include "canvas/CCanvas.h"
#include "units/IUnit.h"

QStack<QPointer<CProgressDialog>> CProgressDialog::stackSelf;

#define DELAY 500

CProgressDialog::CProgressDialog(const QString text, int min, int max, QWidget* parent) : QDialog(parent) {
  stackSelf.push(this);
  int oldTopIndex = stackSelf.length() - 2;

  setupUi(this);
  setWindowModality(Qt::ApplicationModal);

  label->setText(text);
  progressBar->setMinimum(min);
  progressBar->setMaximum(max);
  progressBar->setValue(0);

  time.start();
  labelTime->setText(tr("Elapsed time: %1").arg(time.elapsed() / 1000));

  if (max == NOINT) {
    progressBar->hide();
    // add a timer to update the elapsed time
    QTimer* t = new QTimer(this);
    t->start(DELAY);
    connect(t, &QTimer::timeout, this, [this] { setValue(0); });
  }

  QDialog::hide();
  timer = new QTimer(this);
  timer->setSingleShot(true);
  connect(timer, &QTimer::timeout, this, [this, oldTopIndex] {
    if (oldTopIndex > 0 && !stackSelf[oldTopIndex].isNull()) {
      stackSelf[oldTopIndex]->pause();
    }
    show();
  });
  timer->start(DELAY);
  CCanvas::setOverrideCursor(Qt::ArrowCursor, "CProgressDialog");
}

CProgressDialog* CProgressDialog::self() {
  if (stackSelf.isEmpty()) {
    return nullptr;
  }
  return stackSelf.top();
}

CProgressDialog::~CProgressDialog() {
  stackSelf.pop();
  if (!stackSelf.isEmpty() && !stackSelf.top().isNull()) {
    stackSelf.top()->goOn();
  }
  CCanvas::restoreOverrideCursor("~CProgressDialog");
}

void CProgressDialog::pause() {
  hide();
  timer->stop();
  timeElapsed = time.elapsed();
}

void CProgressDialog::goOn() {
  // if goOn() is called from the dtor of another progress bar this progress bar was not necessarily paused.
  // Also, it the second of waiting might not have elapsed. Thus, if the timer is still running, we do nothing
  if (timer->isActive()) {
    return;
  }
  // after restarting a paused timer we assume the timer would have expired in the meanwhile. Therefore start it again
  // to expire asap.
  timer->start(1);
}

void CProgressDialog::setAllVisible(bool yes) {
  if (stackSelf.isEmpty() || stackSelf.top().isNull()) {
    return;
  }

  yes ? stackSelf.top()->goOn() : stackSelf.top()->pause();
}

void CProgressDialog::enableCancel(bool yes) { buttonBox->setEnabled(yes); }

void CProgressDialog::reject() {
  setResult(QMessageBox::Abort);
  emit rejected();
}

void CProgressDialog::setValue(int val) {
  QApplication::processEvents();
  progressBar->setValue(val);
  labelTime->setText(tr("Elapsed time: %1 seconds.").arg(time.elapsed() / 1000.0, 0, 'f', 0));
}

bool CProgressDialog::wasCanceled() { return result() == QMessageBox::Abort; }

void CProgressDialog::showEvent(QShowEvent*) {
  // that is a workaround for canvas loosing mousetracking caused by CProgressDialog being modal:
  CCanvas* canvas = CMainWindow::self().getVisibleCanvas();
  if (canvas != nullptr) {
    canvas->mouseTrackingLost();
  }
}
