#ifndef GR_CellSkel
#define GR_CellSkel 1

#include "GR_config.h"
#include "GR_Entity.h"
#include "GR_misc.h"
#include "GR_Vertex.h"

class CellSkel : public Entity {
public:
  ///
  enum eCellType {eTriCell = 0, eQuadCell, eTet, ePyr, ePrism, eHex,
		  eBdryEdge, eIntBdryEdge, eTriBFace, eIntTriBFace,
		  eQuadBFace, eIntQuadBFace,
		  eTriCV, eQuadCV, eTetCV, ePyrCV, ePrismCV, eHexCV,
		  eInvalid};
  ///
  enum eCellClass {eUnknown = 0, eWellShaped, eTetNeedle, eTetWedge,
		   eTetSpindle, eTetSliver, eTetCap};
protected:
  // This data doesn't all get used by all CellSkel descendents, but it
  // makes sense to define it here, because that way the bitfields
  // really get packed tightly by the compiler.
  unsigned int uiShapeClass:6, uiRegion:iRegionBits, uiType:5;
  bool qSizeOK:1, qIsDeleted:1, qIsStructured:1;
  ///
  // added by Charles Boivin, Aug 31, 1999
  // Used for redrawing purposes..
  bool qAngleSelected:1;
  //	bool qAlwaysWellSized;
  ///
  CellSkel& operator=(const CellSkel& CS) {
    if (&CS != this) {
      vCopyAllFlags(CS);
    }
    return *this;
  }
public:
  ///
  CellSkel() {vSetDefaultFlags();}
  ///
  virtual ~CellSkel() {}
  ///
  bool qValid() const {return(this != NULL);}
  ///
  // Asks if it is a bdry cell.. return false by default
  virtual bool qIsBdryCell() const {return false;}
  ///
  virtual int iFullCheck() const;
  ///
  void vSetDefaultFlags() {
    uiShapeClass = eUnknown;
    uiRegion = 1;
    // Type is not reset; this is set once and for all by the
    // derived-class constructor.
    qSizeOK = false;
    qIsDeleted = false;
    qIsStructured = false;
    qAngleSelected = false;
  }
  ///
  void vCopyAllFlags(const CellSkel &C) {
    uiShapeClass = C.uiShapeClass;
    uiRegion = C.uiRegion;
    uiType = C.uiType;
    qSizeOK = C.qSizeOK;
    qIsDeleted = C.qIsDeleted;
    qAngleSelected = C.qAngleSelected;
    qIsStructured = C.qIsStructured;
  }
  ///
  void vSetRegion(const int iReg) {
    assert(iReg >= 0 && iReg < iMaxRegionLabel);
    uiRegion = iReg;
  }
  ///
  int iRegion() const {assert(qValid()); return uiRegion;}
  ///
  void vSetShapeClass(const int iClassIn) {uiShapeClass = iClassIn;}
  ///
  int iShapeClass() const {assert(qValid()); return uiShapeClass;}
  ///
  void vMarkWellShaped() {vSetShapeClass(eWellShaped);}
  ///
  bool qWellShaped() const {return (iShapeClass() == eWellShaped);}
  ///
  int eType() const {assert(qValid()); return uiType;}
  ///
  void vSetType(const eCellType eCT) {uiType = eCT;}
  ///
  void vMarkDeleted() {qIsDeleted = true;}
  ///
  void vMarkNotDeleted() {qIsDeleted = false;}
  ///
  bool qDeleted() const {assert(qValid()); return qIsDeleted;}
  ///
  void vMarkQuasiStructured() {
    qIsStructured = true;
    for (int iV = iNumVerts()-1; iV >= 0; iV--) {
      pVVert(iV)->vMarkStructured();
    }
  }
  ///
  void vMarkNotQuasiStructured() {
    qIsStructured = false;
    for (int iV = iNumVerts()-1; iV >= 0; iV--) {
      pVVert(iV)->vClearStructured();
    }
  }
  ///
  bool qIsQuasiStructured() const {assert(qValid()); return qIsStructured;}
  ///
  void vMarkWellSized() {qSizeOK = true;}
  ///
  void vMarkIllSized() {qSizeOK = false;}
  ///
  bool qWellSized() const {assert(qValid()); return qSizeOK;}
  ///
  // Added by Charles Boivin, Aug 9 1999
  // This is used to redraw the mesh more efficiently..
  void vMarkAngleSelected(bool qS) {qAngleSelected = qS;}
  bool qIsAngleSelected() {return qAngleSelected;}
   ///
  virtual int iNumFaces() const = 0;
  ///
  virtual int iNumVerts() const = 0;
  ///
  virtual const Vert* pVVert(const int i) const = 0;
  ///
  virtual Vert* pVVert(const int i) = 0;
  ///
  virtual bool qHasVert(const Vert* pV) const;
  ///
  virtual double dSize() const {assert(0); return -1.e300;}
  ///
  double dMaxDihed() const;
  ///
  double dMinDihed() const;
  ///
  double dMaxSolid() const;
  ///
  double dMinSolid() const;
  ///
  virtual void vAllDihed(double adDihed[], int* const piNDihed) const = 0;
  ///
  virtual void vAllSolid(double adSolid[], int* const piNSolid) const = 0;
  ///
  virtual double dShortestEdgeLength() const {assert(0); return -1.e300;}
};

#endif
