/*****************************************************************************
 * $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 MESH_QUALITY_H
#define MESH_QUALITY_H

#include <Action.h>
#include <MeshComponent.h>

#include <QFrame>
#include <QLabel>
#include <QTableWidget>
#include <QComboBox>

#include <vtkDoubleArray.h>

/**
 * @ingroup group_sdk_actions_mesh_basicmesh
 *
 * @brief
 * Display mesures of mesh quality listed by element types.
 *
 *  \verbatim
   @techreport{knupp2006verdict,
   title={The verdict geometric quality library.},
   author={Knupp, Patrick Michael and Ernst, CD and Thompson, David C and Stimpson, CJ and Pebay, Philippe Pierre},
   year={2006},
   institution={Sandia National Laboratories}
   }
   \endverbatim
 *
 * \image html actions/basic_mesh_quality.png "The mesh quality widget." width=10cm
 *
 */
class MeshQuality : public camitk::Action {
    Q_OBJECT
public:
    /// the constructor
    MeshQuality(camitk::ActionExtension*);

    /// the destructor
    virtual ~MeshQuality() = default;

    /// method called when the action when the action is triggered (i.e. started)
    virtual QWidget* getWidget() override;

public slots:
    /// method called when the action is applied
    virtual camitk::Action::ApplyStatus apply() override;

    /// method called when the selected item in elementsComboBox is changed
    void updateComboBox(int i);

    /// method called when the selected item in qualityMeasureComboBox is changed
    void computeMeasure(int i);

private:
    /// this action widget (to simplify, it is just a label that gives mesh quality information)
    QFrame* informationFrame;

    /// the information label (needed as an attributes to update the displayed text)
    QLabel* informationLabel;

    /// the list of quality informations
    QTableWidget* qualityInfo;

    /// list of elements describing the current mesh
    QComboBox* elementsComboBox;

    /// list of measure quality computable for one type of element
    QComboBox* qualityMeasureComboBox;

    /// text that gives general mesh quality for one type of element (min max avg)
    QLabel* elementInfoLabel;

    /// true, if slots are connected, false otherwise
    bool isConnected;

    /// name of the current mesh (needed as an attribute to avoid recomputing of tableWidget)
    QString currentMeshName;

    /// map describing index of cell for each type of element (needed as an attribute to update tableWidget)
    std::map<unsigned char, std::vector<vtkIdType> > elementsMap;

    /// minimum and maximum of normal range of a quality measure
    double minNR, maxNR;

    /// minimum and maximum of acceptable range of a quality measure (included in normal range)
    double minAR, maxAR;

    /// minimum and maximum of values found for the concerned mesh. These data are used when ratio are computed or when NormalRange is unbounded
    double minV, maxV;

    /**
     * @brief get the appropriate color between [0;1] for a colorScale
     *
     * @param val input value which determinates the color
     * @param minAR minimum of acceptable range
     * @param maxAR maximum of acceptable range
     * @param minNR minimum of normal range (smaller than minAR)
     * @param maxNR maximum of normal range (greater than maxAR)
     * @return double the color. It is a value between [0:1]
     **/
    double getQualityColor(double val, double minAR, double maxAR, double minNR, double maxNR);

    /**
     * @brief return a rich text describing the mesh
     *
     * @param meshComponent input mesh
     * @return QString the text describing the mesh
     **/
    QString getInfos(camitk::MeshComponent* meshComponent);

    /// update the table widget to display quality measure for each element
    void updateTableWidget(vtkSmartPointer<vtkDoubleArray> qualityArray);
    /// update the mesh to diplay a scalar color to show good and bad elements
    void updateMeshColor(vtkSmartPointer< vtkDoubleArray > qualityArray);

    /// lists defining quality methods for each type of element
    static QStringList trisFuncList;
    static QStringList quadsFuncList;
    static QStringList hexasFuncList;
    static QStringList tetrasFuncList;

    /// methods to compute the correct quality from a mesh
    vtkSmartPointer<vtkDoubleArray> computeTrisQuality(camitk::MeshComponent* meshComponent, int qualityTest);
    vtkSmartPointer<vtkDoubleArray> computeTetrasQuality(camitk::MeshComponent* meshComponent, int qualityTest);
    vtkSmartPointer<vtkDoubleArray> computeHexasQuality(camitk::MeshComponent* meshComponent, int qualityTest);
    vtkSmartPointer<vtkDoubleArray> computeQuadsQuality(camitk::MeshComponent* meshComponent, int qualityTest);
};
#endif // MESH_QUALITY_H
