////////////////////////////////////////////////////////////////////////////////////////
//
//  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/gui/desktop/GUI.h>
#include <ovito/gui/desktop/widgets/general/ActionsItemDelegate.h>
#include <ovito/core/oo/RefTargetListener.h>

namespace Ovito {

/**
 * A Qt model/view system list model that contains all scene nodes in the current scene.
 */
class OVITO_GUI_EXPORT SceneNodesListModel : public QAbstractListModel, public UserInterfaceComponent<MainWindowUI>
{
    Q_OBJECT

public:

    /// Additional custom roles used by the item delegate to fetch data from the model.
    enum ItemRoles {
        InfoRole = Qt::UserRole + 1,
        ActionsRole = Qt::UserRole + 2,
    };

    /// Constructor.
    explicit SceneNodesListModel(MainWindowUI& ui, QWidget* parent = nullptr);

    /// Returns the number of rows of the model.
    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;

    /// Returns the model's data stored under the given role for the item referred to by the index.
    virtual QVariant data(const QModelIndex& index, int role) const override;

    /// Returns the item flags for the given index.
    virtual Qt::ItemFlags flags(const QModelIndex& index) const override;

    /// Returns the current scene.
    Scene* scene() const { return _sceneListener.target(); }

    /// Returns the current list of scene nodes in the scene.
    const auto& sceneNodes() const { return _nodeListener.targets(); }

    /// Returns the scene node at the given index of the list model.
    SceneNode* sceneNodeFromListIndex(int index) const {
        int nodeIndex = index - firstSceneNodeIndex();
        return (nodeIndex >= 0 && nodeIndex < sceneNodes().size()) ? sceneNodes()[nodeIndex] : nullptr;
    }

public Q_SLOTS:

    /// This slot executes the action associated with the given list item.
    void activateItem(int index);

    /// Toggles the visibility of a scene node in all viewports.
    void toggleNodeVisibility(const QModelIndex& index);

    /// Deletes a scene node.
    void deleteSceneNode(const QModelIndex& index);

    /// Lets the user rename a scene node.
    void renameSceneNode(const QModelIndex& index);

Q_SIGNALS:

    /// This signal is emitted by the model to request a selection change in the widget it is attached to.
    void selectionChangeRequested(int index);

private Q_SLOTS:

    /// This is called when a new scene becomes active.
    void onSceneReplaced(Scene* newScene);

    /// This is called whenever a different scene node has been selected by the user.
    void onSceneSelectionChanged(SelectionSet* selection);

    /// This handles reference events generated by the scene root node.
    void onSceneNotificationEvent(RefTarget* source, const ReferenceEvent& event);

    /// This handles reference events generated by the scene nodes.
    void onNodeNotificationEvent(RefTarget* source, const ReferenceEvent& event);

    /// Updates the color brushes of the model.
    void updateColorPalette(const QPalette& palette);

    /// Refreshes the list items that have been marked for a deferred update.
    void deferredNodeUpdate();

private:

    /// Returns the list index of the first scene node item.
    int firstSceneNodeIndex() const { return 1; }

    /// Returns the list index of the first action item.
    int firstActionIndex() const { return sceneNodes().empty() ? 3 : (2 + sceneNodes().size()); }

    /// Used to receive reference events generated by the scene nodes.
    VectorRefTargetListener<SceneNode> _nodeListener;

    /// Used to receive signals sent by the scene root node.
    RefTargetListener<Scene> _sceneListener;

    /// The actions that are displayed as list items in the combobox.
    QVector<QAction*> _pipelineActions;

    /// The background brush used for list section headers.
    QBrush _sectionHeaderBackgroundBrush;

    /// The foreground brush used for list section headers.
    QBrush _sectionHeaderForegroundBrush;

    /// Icon representing a pipeline scene node.
    QIcon _pipelineSceneNodeIcon;

    /// Fonts for rendering selected and/or hidden scene nodes.
    QFont _selectedNodeFont;
    QFont _hiddenNodeFont;
    QFont _selectedHiddenNodeFont;

    /// List items to be updated only occasional.
    QVector<SceneNode*> _deferredUpdateList;

    /// Action for toggling the visibility of a pipeline when it is currently visible.
    ItemAction* _visibilityOnAction;

    /// Action for toggling the visibility of a pipeline when it is currently hidden.
    ItemAction* _visibilityOffAction;

    /// Action for renaming a pipeline.
    ItemAction* _renameAction;

    /// Action for deleting a pipeline.
    ItemAction* _deleteAction;
};

}   // End of namespace
