/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef PMLEXPLORERWIDGET_H
#define PMLEXPLORERWIDGET_H

// Qt includes
#include <QWidget>
#include <QMap>
class QTreeWidgetItem;

// Qt Designer generated .ui
namespace Ui {
class ui_PmlExplorerWidget;
}

namespace camitk {
class ObjectController;
}

// CamiTK forward declaration
class PMLComponent;
class CamiTKPropertyList;

// Pml forward declaration
class PhysicalModel;
class MultiComponent;
class StructuralComponent;
class Atom;
class Cell;
class Component;


/** This class is the Pml explore action widget presented/controller.
  * It allows one to map the graphical treeview widget from the pml object.
  *
  * Considering the MVP pattern:
  * - M = the PMLComponent and the PhysicalModel instances it encapsulates
  * - V = the Qt Widget build using Qt Designer (ui_pmlExploreWidget)
  * - P = this class, it uses the data in the PMLComponent/PhysicalModel to build the
  *   GUI representation (update the widget) and use the user feedback to modify the
  *   PMLComponent/PhysicalModel.
  */
class PMLExplorerWidget : public QWidget {
    Q_OBJECT

public:
    /// Constructor
    PMLExplorerWidget(PMLComponent* comp);

    /// Destructor
    ~PMLExplorerWidget() override; //{ if (this->ui) delete ui; }

    /// Update the widget content as the input selected component changed.
    void updateTarget(PMLComponent* comp);

public slots:
    /// called when the user click on apply in the object controller
    void propertyChanged();

    /// called when the user click on new in the object controller
    void createNewProperty();

    /// This slot is connected to the corresponding UI Checkbox, update the showAtomGlyph state
    void showAtomGlyphToggled(bool);

private slots:

    /// The slot defined to select the QTreeWidgetItem in its corresponding pml element (SC, MC, Atom or Cell)
    /// to correctly highlight it in the 3D structure and display its properties.
    void selectItems();

private:
    /// The PML Component associated with the action.
    PMLComponent* pmlComponent;

    /// The PML Component to explore with the action
    PhysicalModel* physicalModel;

    /// The graphical user interface automatically generated by the moc and QtDesigner.
    Ui::ui_PmlExplorerWidget* ui;

    /// A pml::component <-> QTreeWidgetItem map to find out, once selected the corresponding pml::Component
    /// (StructuralComponent, MultiComponent or Cell) associated to the QTreeWidgetItem.
    QMap<QTreeWidgetItem*, Component*> widgetComponentMap;

    /// A pml::Atom <-> QTreeWidgetItem map to find out, once selected the corresponding pml::Atom associated
    /// to the QTreeWidgetItem.
    QMap<QTreeWidgetItem*, Atom*> widgetAtomMap;

    /// Map QTreeWidgetItem <-> CamiTKPropertyList for all PML components (Cell, SC, MC).
    /// A CamiTKPropertyList is build if not already build, it allows the user to interact with
    /// the physical model field attributes/properties using the explorer's ObjectController.
    /// This is only used for PML components (Cell, SC, MC) not for atoms
    /// The only exception is for the PMLComponent holding the top-level physicalModel properties:
    /// it is not a CamiTKPropertyList but directly a QObject
    QMap<QTreeWidgetItem*, QObject*> widgetPropertiesMap;

    /// Map QTreeWidgetItem <-> CamiTKPropertyList for atom
    /// For the atoms, there is only one CamiTKPropertyList per atom
    QMap<Atom*, QObject*> atomPropertiesMap;

    /// build a QObject from physical model properties
    void updateProperty(QTreeWidgetItem*);

    /// the QObject are displaying properties in the ObjectController
    camitk::ObjectController* objectController;

    /// item being currently edited
    QTreeWidgetItem* editedItem;

    /// the state of the show atom glyph checkbox
    bool showAtomGlyph;

    /// @name Tree widget item management
    ///@{

    /// initialize component, physicalmodel and interaction
    void init(PMLComponent*);

    /// The main tree widget items, at the base of the structure
    QTreeWidgetItem* physicalModelItem;

    /// the atom SC tree widget item
    QTreeWidgetItem* atomsItem;

    /// the exclusive component MC tree widget item
    QTreeWidgetItem* exclusiveComponentItem;

    /// the informative component MC tree widget item
    QTreeWidgetItem* informativeComponentItem;

    /// Parse the basic contents of the PML component: its atoms, exclusive and informative components
    /// and call other methods to fill the widget with the pml structure.
    /// @return the top-level item
    void buildPhysicalModelTreeWidgetItem();

    /// Recursive method to add an entry for the current multicomponent to the widget.
    /// @param multiComponent the current multiComponent to add to the widget
    /// @param parent the parent QTreeWidgetItem
    /// @return the top-level item
    QTreeWidgetItem* buildMultiComponentTreeWidgetItem(MultiComponent* multiComponent, QTreeWidgetItem* parent);

    /// Add an entry for the current structural component to the widget.
    /// @param sc the current structural component to add to the widget
    /// @param parent the parent QTreeWidgetItem
    /// @return the top-level item
    QTreeWidgetItem* buildStructuralComponentTreeWidgetItem(StructuralComponent* sc, QTreeWidgetItem* parent);

    /// Add an entry for the current cell to the widget
    /// @param cell the current cell parsed to add to the widget
    /// @param parent the parent QTreeWidgetItem
    /// @return the top-level item
    QTreeWidgetItem* buildCellTreeWidgetItem(Cell* cell, QTreeWidgetItem* parent);

    /// Add an entry for the current atom to the widget
    /// @param atom the current atom parsed to add to the widget
    /// @param parent the parent QTreeWidgetItem
    /// @return the atom item
    QTreeWidgetItem* buildAtomTreeWidgetItem(Atom* atom, QTreeWidgetItem* parent);
    ///@}

    /// @name PML components and atoms properties
    ///@{
    /// Creates a CamiTKPropertyList for this atom or get the existing one
    CamiTKPropertyList* createAtomPropertyList(Atom*);

    /// Creates a CamiTKPropertyList for this cell or get the existing one
    CamiTKPropertyList* createCellPropertyList(Cell*);

    /// Creates a CamiTKPropertyList for this MC or get the existing one
    CamiTKPropertyList* createMCPropertyList(MultiComponent*);

    /// Creates a CamiTKPropertyList for this SC or get the existing one
    CamiTKPropertyList* createSCPropertyList(StructuralComponent*);

    ///@}
};


#endif // PMLEXPLORERWIDGET_H