////////////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2026 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>
#include <ovito/core/oo/RefTarget.h>
#include <ovito/core/dataset/pipeline/PipelineStatus.h>

namespace Ovito {

/**
 * \brief Abstract base class for objects perform long-running computations and which
 *        can be enabled or disabled.
 */
class OVITO_CORE_EXPORT ActiveObject : public RefTarget
{
    OVITO_CLASS(ActiveObject)

public:

    /// Custom notification event types generated by this class:
    enum {
        /// This event is generated by the ActiveObject when it became active or inactive.
        ActivityChanged = RefTarget::NEXT_AVAILABLE_EVENT_ID,

        /// End-of-list value indicating the next available event type that can be used by sub-classes for custom notifications.
        NEXT_AVAILABLE_EVENT_ID
    };

    /// Returns the title of this object.
    virtual QString objectTitle() const override {
        if(title().isEmpty())
            return RefTarget::objectTitle();
        else
            return title();
    }

    /// Changes the title of this object.
    void setObjectTitle(const QString& title) {
        setTitle(title);
    }

    /// Returns true if at least one computation task associated with this object is currently active.
    bool isObjectActive() const { return _numberOfActiveTasks != 0; }

    /// Returns a short piece of information (typically a string or color) to be displayed next to the object's title in the pipeline editor.
    virtual QVariant getPipelineEditorShortInfo(Scene* scene) const;

    /// Registers the given future as an active task associated with this object.
    void registerActiveFuture(const FutureBase& future);

    /// Displays the given status information in the GUI for this object.
    /// The status is only displayed if the current frame of the pipeline matches the frame
    /// for which the status was generated.
    void setStatusIfCurrentFrame(const PipelineStatus& status, const PipelineEvaluationRequest& request);

protected:

    /// Is called when the value of a non-animatable property field of this RefMaker has changed.
    virtual void propertyChanged(const PropertyFieldDescriptor* field) override;

    /// Increments the internal task counter and notifies the UI that this object is currently active.
    void incrementNumberOfActiveTasks();

    /// Decrements the internal task counter and, if the counter has reached zero, notifies the
    /// UI that this object is no longer active.
    void decrementNumberOfActiveTasks();

private:

    /// Controls whether the object is currently enabled.
    DECLARE_MODIFIABLE_PROPERTY_FIELD(bool{true}, isEnabled, setEnabled);
    DECLARE_SHADOW_PROPERTY_FIELD(isEnabled);

    /// The user-defined title of this object.
    DECLARE_MODIFIABLE_PROPERTY_FIELD(QString{}, title, setTitle);
    DECLARE_SHADOW_PROPERTY_FIELD(title);

    /// The current status of this object.
    DECLARE_MODIFIABLE_PROPERTY_FIELD_FLAGS(PipelineStatus{}, status, setStatus, PROPERTY_FIELD_NO_UNDO | PROPERTY_FIELD_NO_CHANGE_MESSAGE | PROPERTY_FIELD_DONT_SERIALIZE);

    /// Indicates how many running tasks are currently associated with this object.
    int _numberOfActiveTasks = 0;
};

}   // End of namespace
