#ifndef GR_BFace
#define GR_BFace 1

class BFace;

#include "GR_config.h"

#include "GR_misc.h"
#include "GR_Cell.h"

enum eEncroachType {eBall, eLens, eNewLens};
enum eEncroachResult {eClean, eSplit, eOffsetPoint};

// A boundary face is a Cell so that a Face can point to it just like
// any other Cell.  This gives a Face access to its BC if that's needed,
// for example, while making all Faces look exactly the same for stuff
// other than BC's.  At the same time, BFace's can walk right into the
// mesh by way of the actual Face to which they're attached.  The Cell
// dSize and vAllDihed member functions are also useful here; the former
// is overloaded to evaluated surface area of a BFace and the latter to
// evaluate angles in the surface mesh.

class BFace : public Cell {
protected:
  // Some data required for point insertion at/near boundaries.
  mutable bool qOffsetInsRequested:1, qNeverDoOffsetIns:1;
  mutable double adInsertionLoc[3];
  // Copy construction disallowed, but must be declared protected so
  // that derived classes can pretend to use it.
  BFace(const BFace& BF) : Cell(BF), qOffsetInsRequested(false),
    qNeverDoOffsetIns(false) {assert(0);}
  // Called only by more-derived classes; all args provided.
  BFace(const bool qIsInternal, Face* const pFLeft, Face* const pFRight)
    : Cell(qIsInternal, pFLeft, pFRight), qOffsetInsRequested(false),
    qNeverDoOffsetIns(false)
    {
      adInsertionLoc[0] = adInsertionLoc[1] = adInsertionLoc[2] = 1.e300;
    }
private:
  // These are functions needed for TSTT support, and TSTT doesn't
  // recognize the existence of such a thing as BFace's, so these can
  // all be private and garbage.
  int iNumCells() const {assert(0); return 1;}
#ifdef ITAPS
  int iTopologicalDimension() const {assert(0); return -1;}
  int eEntType() const {assert(0); return iBase_ALL_TYPES;}
  int eEntTopology() const {assert(0); return iMesh_ALL_TOPOLOGIES;}
#endif
  void vAllVertHandles(GRUMMP_Entity*[]) const {assert(0);}
  void vAllFaceHandles(GRUMMP_Entity*[]) const {assert(0);}
  void vAllCellHandles(GRUMMP_Entity*[]) const {assert(0);}
public:
  // The destructor has nothing to do.
  virtual ~BFace() {}
  // Necessary when (for example) removing deleted BFace's from VarArray's
  BFace& operator=(const BFace& BF);
  // This is implemented differently in 2D and 3D.
  virtual int iBdryCond() const = 0;
  // Is there any point in the mesh that encroaches on this BFace?
  virtual enum eEncroachResult eIsEncroached(const enum eEncroachType eET
					     = eLens) const = 0;
  enum eEncroachResult eIsPointEncroaching(const double adPoint[],
					   const enum eEncroachType eET
					     = eLens,
					   const bool qTieBreaker = false) const
    {
      switch (eET) {
      case eBall:
	return eIsPointEncroachingBall(adPoint, qTieBreaker);
      case eLens:
	return eIsPointEncroachingLens(adPoint, qTieBreaker);
      case eNewLens:
	return eIsPointEncroachingNewLens(adPoint, qTieBreaker);
      default:
	assert(0);
	return(eClean);
      }
    }
  virtual enum eEncroachResult
    eIsPointEncroachingBall(const double adPoint[],
			    const bool qTieBreak = false) const = 0;
  virtual enum eEncroachResult
    eIsPointEncroachingLens(const double adPoint[],
			    const bool qTieBreak = false) const = 0;
  virtual enum eEncroachResult
    eIsPointEncroachingNewLens(const double adPoint[],
			       const bool qTieBreak = false) const = 0;
  virtual double dInsertionPriority() const {assert(0); return 0;}
  virtual void vGetOffsetInsertionPoint(const double[],	double[]) const
    {assert(0);}
  const double* adInsertionLocation() const {return adInsertionLoc;}
  virtual void vSetInsertionLocation(const double[]) const {assert(0);}
  bool qOffsetInsertionRequested() const {return qOffsetInsRequested;}
  void vRequestOffsetInsertion() const {qOffsetInsRequested = true;}
  void vClearOffsetInsertionRequest() const {qOffsetInsRequested = false;}
  bool qOffsetInsertionAllowed() const {return !qNeverDoOffsetIns;}
  void vForbidOffsetInsertion() const
    {qNeverDoOffsetIns = true; qOffsetInsRequested = false;}
  void vAllowOffsetInsertion() const {qNeverDoOffsetIns = false;}
  virtual void vCircumcenter(double []) const = 0;
  // Closure makes no sense for BFace's
  bool qIsClosed() const {return true;}
  // It is a bdry face/cell...
  virtual bool qIsBdryCell() const {return true;}
  Face *pFFace(const int i = 0)
    {
      assert(i < iNumFaces());
      return(ppFFaces[i]);
    }
  const Face *pFFace(const int i = 0) const
    {
      assert(i < iNumFaces());
      return(ppFFaces[i]);
    }
  const Vert* pVVert(const int i) const;
  Vert* pVVert(const int i) {
    return const_cast<Vert*>(static_cast<const BFace*>(this)->pVVert(i));
  }
  double dSize() const;
  void vVecSize(double adRes[]) const;
  void vUnitNormal(double adRes[]) const;
  virtual void vSetPatch(BdryPatch* const pBP) = 0;
  virtual BdryPatch* pPatchPointer() const = 0;
  virtual void vCentroid(double[]) const {assert(0);}
}; // End of BFace base class declaration

#endif
