//=========================================================================
//  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 "smtk/simulation/ace3p/qt/qtAbstractJobTracker.h"

#include <QDebug>

#ifndef NDEBUG
#include <iostream>
#endif

namespace
{
// Macro for printing messages to stdout for debug builds only
#ifndef NDEBUG
#define DebugMessageMacro(msg)                                                                     \
  do                                                                                               \
  {                                                                                                \
    std::cout << __FILE__ << ":" << __LINE__ << " " << msg << std::endl;                           \
  } while (0)
#else
#define DebugMessageMacro(msg)
#endif
} // namespace

namespace smtk
{
namespace simulation
{
namespace ace3p
{
//-----------------------------------------------------------------------------
qtAbstractJobTracker::qtAbstractJobTracker(QObject* parent)
  : Superclass(parent)
{
  m_internalTimer = new qtAbstractJobTracker::InternalTimer;
}

qtAbstractJobTracker::~qtAbstractJobTracker()
{
  delete m_internalTimer;
}

void qtAbstractJobTracker::addJob(const QString& jobId, bool checkUnique)
{
  if (checkUnique && this->m_jobList.contains(jobId))
  {
    DebugMessageMacro("Job list already contains " << jobId.toStdString());
    return;
  }

  this->m_jobList.push_back(jobId);
  this->setNextPoll();
}

void qtAbstractJobTracker::addNewJob(const QString& jobId)
{
  this->m_jobList.push_back(jobId);
  this->setNextPoll(true);
}

bool qtAbstractJobTracker::enablePolling(bool enable)
{
  bool wasPolling = this->isPolling();
  m_internalTimer->m_pollingEnabled = enable;
  if (enable)
  {
    bool started = this->setNextPoll(true);
    return started;
  }
  else
  {
    m_internalTimer->m_timer->stop();
    if (wasPolling)
    {
      emit this->pollingStateChanged(false);
    }
    DebugMessageMacro("Polling timer stopped.");
  }

  return false;
}

bool qtAbstractJobTracker::isPolling() const
{
  if (!m_internalTimer->m_pollingEnabled)
  {
    return false;
  }
  return m_internalTimer->m_busy || m_internalTimer->m_timer->isActive();
}

void qtAbstractJobTracker::setPollingIntervalSeconds(const int intervalSec)
{
  m_internalTimer->m_timer->setInterval(1000 * intervalSec);
}

int qtAbstractJobTracker::pollingIntervalSeconds() const
{
  return 1000 * m_internalTimer->m_timer->interval();
}

bool qtAbstractJobTracker::setNextPoll(bool pollNow)
{
  bool wasPolling = this->isPolling();
  if (!m_internalTimer->m_pollingEnabled)
  {
    return false;
  }

  if (this->m_jobList.isEmpty())
  {
    DebugMessageMacro("Polling list empty.");
    m_internalTimer->m_busy = false;
    if (wasPolling)
    {
      emit this->pollingStateChanged(false);
    }
    return false;
  }

  if (pollNow)
  {
    // Use 1000 msec to give time for queue id to be assigned
    QTimer::singleShot(1000, this, &qtAbstractJobTracker::onTimerEvent);
  }
  else
  {
    m_internalTimer->m_timer->start();
  }

  DebugMessageMacro("Polling timer started.");
  if (!wasPolling)
  {
    emit this->pollingStateChanged(true);
  }
  return true;
}

void qtAbstractJobTracker::onTimerEvent()
{
  DebugMessageMacro("onTimerEvent");
  int i = static_cast<int>(this->m_jobList.size() - 1);
  // Check that index is still valid (i.e., that list hasn't been cleared)
  if (i < 0)
  {
    emit this->pollingStateChanged(false);
    return;
  }
  this->requestJob(i);
}

void qtAbstractJobTracker::clear()
{
  bool wasPolling = this->isPolling();

  m_internalTimer->m_timer->stop();
  m_internalTimer->m_busy = false;
  m_internalTimer->m_pollingIndex = -1;
  this->m_jobList.clear();

  if (wasPolling)
  {
    emit this->pollingStateChanged(false);
  }
}

bool qtAbstractJobTracker::pollOnce()
{
  if (m_internalTimer->m_pollingEnabled)
  {
    qInfo() << "Cannot use pollOnce() when continuous polling enabled.";
    return false;
  }

  if (m_internalTimer->m_busy)
  {
    qInfo() << "Already polling.";
    return false;
  }

  if (this->m_jobList.isEmpty())
  {
    qInfo() << "No jobs in polling list.";
    return false;
  }

  // Start with last job in the list and work to the front,
  // so that we can remove jobs form the list without changing the other indices.
  int i = static_cast<int>(this->m_jobList.size() - 1);
  this->requestJob(i);
  return true;
}

} // namespace ace3p
} // namespace simulation
} // namespace smtk
