////////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2023 OVITO GmbH, Germany
//
//  This file is part of OVITO (Open Visualization Tool).
//
//  OVITO is free software; you can redistribute it and/or modify it either under the
//  terms of the GNU General Public License version 3 as published by the Free Software
//  Foundation (the "GPL") or, at your option, under the terms of the MIT License.
//  If you do not alter this notice, a recipient may use your version of this
//  file under either the GPL or the MIT License.
//
//  You should have received a copy of the GPL along with this program in a
//  file LICENSE.GPL.txt.  You should have received a copy of the MIT License along
//  with this program in a file LICENSE.MIT.txt
//
//  This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
//  either express or implied. See the GPL or the MIT License for the specific language
//  governing rights and limitations.
//
////////////////////////////////////////////////////////////////////////////////////////

#pragma once


#include <ovito/core/Core.h>

namespace Ovito {

/**
 * \brief Manages the background tasks.
 */
class OVITO_CORE_EXPORT TaskManager : public QObject
{
    Q_OBJECT

public:

    /// Constructor.
    TaskManager();

#ifdef OVITO_DEBUG
    /// Destructor.
    virtual ~TaskManager();
#endif

    /// \brief Returns the watchers for all currently running tasks.
    /// \return A list of TaskWatcher objects, one for each registered task that is currently in the 'started' state.
    /// \note This method is *not* thread-safe and may only be called from the main thread.
    const std::vector<TaskWatcher*>& runningTasks() const { return _runningTasks; }

    /// \brief Returns the watchers for all currently registered tasks.
    /// \return A list of TaskWatcher objects, one for each registered task that has not yet reached the 'finished' state.
    /// \note This method is *not* thread-safe and may only be called from the main thread.
    QList<TaskWatcher*> registeredTasks() const;

    /// \brief Registers a future with the TaskManager, which will subsequently track the progress of the associated operation.
    /// \param future The Future whose shared state should be registered.
    /// \note This function is thread-safe.
    /// \sa registerTask()
    /// \sa FutureBase::task()
    void registerFuture(const FutureBase& future);

    /// \brief Registers a promise with the TaskManager, which will subsequently track the progress of the associated operation.
    /// \param promise The Promise whose shared state should be registered.
    /// \note This function is thread-safe.
    /// \sa registerTask()
    /// \sa PromiseBase::task()
    void registerPromise(const PromiseBase& promise);

    /// \brief Registers a Task with the TaskManager, which will subsequently track the progress of the associated operation.
    /// \note This function is thread-safe.
    void registerTask(const TaskPtr& task);

    /// \brief Registers a Task with the TaskManager, which will subsequently track the progress of the associated operation.
    /// \note This function is thread-safe.
    void registerTask(Task& task);

    /// \brief Returns whether printing of task status messages to the console is currently enabled.
    bool consoleLoggingEnabled() const { return _consoleLoggingEnabled; }

    /// \brief Enables or disables printing of task status messages to the console for this task manager.
    void setConsoleLoggingEnabled(bool enabled);

    /// Indicates whether the session is in the processing of shutting down.
    bool isShuttingDown() const { return _isShuttingDown; }

#ifdef OVITO_USE_SYCL
    /// Returns the main SYCL out-of-order queue to which work can be submitted.
    SYCL_NS::queue& syclQueue() { return _syclQueue; }
#endif

public Q_SLOTS:

    /// \brief Cancels all running tasks and waits for them to finish.
    void shutdown();

Q_SIGNALS:

    /// \brief This signal is generated by the task manager whenever one of the registered tasks started to run.
    /// \param watcher The TaskWatcher can be used to track the operation's progress.
    void taskStarted(TaskWatcher* taskWatcher);

    /// \brief This signal is generated by the task manager whenever one of the registered tasks has finished or stopped running.
    /// \param watcher The TaskWatcher that was used by the task manager to track the running task.
    void taskFinished(TaskWatcher* taskWatcher);

    /// This signal is emitted when the number of active tasks drops to zero.
    void allTasksFinished();

private:

    /// \brief Registers a promise with the progress manager.
    Q_INVOKABLE void addTaskInternal(const TaskPtr& sharedState);

private Q_SLOTS:

    /// \brief Is called when a task has started to run.
    void taskStartedInternal();

    /// \brief Is called when a task has finished.
    void taskFinishedInternal();

    /// \brief Is called when a task has reported a new progress text (only if logging is enabled).
    void taskProgressTextChangedInternal(const QString& msg);

private:

    /// The list of watchers for the active tasks.
    std::vector<TaskWatcher*> _runningTasks;

    /// Enables printing of task status messages to the console.
    bool _consoleLoggingEnabled = false;

    /// Indicates whether the session is in the processing of shutting down.
    bool _isShuttingDown = false;

#ifdef OVITO_USE_SYCL
    /// The main SYCL out-of-order queue for work on the compute device.
    SYCL_NS::queue _syclQueue;

    /// The head of the linked list of RegisteredBufferAccess objects associated with this task manager's SYCL queue.
    RegisteredBufferAccess* _registeredBufferAccessors = nullptr;
#endif

    friend class Task;
    friend class RegisteredBufferAccess;
};

}   // End of namespace
