////////////////////////////////////////////////////////////////////////////////////////
//
//  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/base/GUIBase.h>
#include <ovito/core/oo/RefTarget.h>
#include <ovito/core/oo/RefTargetListener.h>
#include <ovito/core/viewport/Viewport.h>
#include "OverlayListItem.h"

namespace Ovito {

/**
 * A Qt model class used to populate the QListView widget on the viewport layer tab of the command panel.
 */
class OVITO_GUIBASE_EXPORT OverlayListModel : public QAbstractListModel, public UserInterfaceComponent<UserInterface>
{
    Q_OBJECT

public:

    enum ItemRoles {
        StatusInfoRole = Qt::UserRole + 1,
    };

    /// Constructor.
    OverlayListModel(QObject* parent, UserInterface& ui);

    /// Returns the number of list items.
    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override { return _items.size(); }

    /// Returns the data associated with a list entry.
    virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;

    /// Changes the data associated with a list entry.
    virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;

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

    /// Returns the associated selection model.
    QItemSelectionModel* selectionModel() const { return _selectionModel; }

    /// Returns the currently selected model item in list.
    OverlayListItem* selectedItem() const;

    /// Returns the ViewportOverlay that is currently selected in the editor.
    ViewportOverlay* selectedLayer() const {
        if(OverlayListItem* item = selectedItem())
            return item->overlay();
        return nullptr;
    }

    /// Returns the currently selected index in the overlay list.
    int selectedIndex() const;

    /// Returns an item from the list model.
    OverlayListItem* item(int index) const {
        OVITO_ASSERT(index >= 0 && index < _items.size());
        return _items[index];
    }

    /// Populates the model with the given list items.
    void setItems(const QList<OORef<OverlayListItem>>& newItems);

    /// Returns the list of items.
    const QList<OORef<OverlayListItem>>& items() const { return _items; }

    /// The currently selected viewport whose overlays are mirrored by this list model.
    Viewport* selectedViewport() const { return _selectedViewport.target(); }

    /// Sets the currently selected viewport whose overlays should be mirrored by this list model.
    void setSelectedViewport(Viewport* viewport) {
        _selectedViewport.setTarget(viewport);
        refreshList();
    }

    /// Sets the overlay that should be selected on the next list update.
    void setNextToSelectObject(ViewportOverlay* obj) { _nextObjectToSelect = obj; }

Q_SIGNALS:

    /// This signal is emitted if a new list item has been selected, or if the currently
    /// selected item has changed.
    void selectedItemChanged();

public Q_SLOTS:

    /// Rebuilds the viewport overlay list.
    void refreshList();

    /// Updates the appearance of a single list item.
    void refreshItem(OverlayListItem* item);

    /// Rebuilds the list of items as soon as possible.
    void requestUpdate() {
        if(_needListUpdate) return; // Update is already pending.
        _needListUpdate = true;
        // Invoke actual refresh function at some later time.
        QMetaObject::invokeMethod(this, "refreshList", Qt::QueuedConnection);
    }

private Q_SLOTS:

    /// Handles notification events generated by the selected viewport.
    void onViewportEvent(RefTarget* source, const ReferenceEvent& event);

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

private:

    /// List of visible items in the model.
    QList<OORef<OverlayListItem>> _items;

    /// Holds reference to the currently selected Viewport.
    RefTargetListener<Viewport> _selectedViewport;

    /// The item in the list that should be selected on the next list update.
    ViewportOverlay* _nextObjectToSelect = nullptr;

    /// The selection model of the list view widget.
    QItemSelectionModel* _selectionModel;

    /// Indicates that the list of items needs to be updated.
    bool _needListUpdate = false;

    // Status icons:
    QIcon _statusWarningIcon;
    QIcon _statusErrorIcon;
    QPixmap _statusNoneIcon;

    /// Font used for section headers.
    QFont _sectionHeaderFont;

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

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

    /// The foreground brush used for list items that are disabled.
    QBrush _disabledForegroundBrush;
};

}   // End of namespace
