#ifndef GR_Quality
#define GR_Quality 1

#include <stdio.h>
#include "GR_config.h"

/// Range 0 - 180
void vMaxDihed(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vMinDihed(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vAllDihed(const CellSkel* const pC, int * const piN, double adRes[]);

/// Range 0 - 360
void vMaxSolid(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vMinSolid(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vAllSolid(const CellSkel* const pC, int * const piN, double adRes[]);

/// Range 0 - 1
void vInToCircumSphere(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vSliverQ1(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vSkewnessQ2(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vVolArea(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vShortestToRadius(const CellSkel* const pC, int * const piN, double adRes[]);

/// Range 0 - 1
void vInToCircumCircle(const CellSkel* const pC, int * const piN, double adRes[]);
///
void vAreaPerim(const CellSkel* const pC, int * const piN, double adRes[]);

///
class Quality {
  ///
  const Mesh *pM;
  ///
  void (*pvfQualityFunc)(const CellSkel* const pC, int * const piN,
			 double adResult[]);
  ///
  int iQualEvals, iMaxEvals, iNBins;
  ///
  double dMaxQual, dMinQual;
  ///
  int *aiNumQualVals;
  ///
  double *adSignifImp; // Statistical measure of the significance of the
                       // improvement in the mesh quality measure since
                       /// the last assessment.
  double **a2dBinFrac;
  ///
  double *adMinQual, *adMaxQual;
  ///
  bool qMaxMin; 
  ///
  int iComputeBin(const double dQual) const;
  ///
  Quality& operator=(const Quality &) {assert(0); return(*this);}
public:
  ///
  Quality(Mesh* const pMIn, const int iMeas);
  ///
  Quality(const Quality &);
  ///
//  Quality(Mesh* const pMIn,
//	  void vQual(const Cell* const, int * const, double * const) =
//	         vAllDihed, 
//	  const int iNB = 30, const double dMin = 0., const double dMax = 180.,
//	  const int iMaxEvals = 20);
  ///
  ~Quality();
  ///
  void vEvaluate();
  /// Evaluate for only one cell.
  double dEvaluate(const CellSkel * const pC) const;
  ///
  void vWriteToFile(char strQualFileName[]) const;
  ///
  double dWorstQuality() const {return adMinQual[iQualEvals-1];}
  ///
  bool qMaximizeMinValue() const {return qMaxMin;}
  ///
  void vSetMesh(const Mesh * const pMIn) {pM = pMIn;}
  ///
  void vImportQualityData(const double adData[]);
};
  

#endif
