#ifndef GR_AnisoFront_Entry
#define GR_AnisoFront_Entry 1

#include "GR_config.h"
#include "GR_Vertex.h"

// The data structure for each element in the front contains:
//  o A pointer to a valid face in the mesh.
//  o The vertices on that face, stored so that
//  o The step size taken to create the face
//  o Pointers to
//      Adjacent front entries (can be NULL if this face is
//          at the end of a front)
//      The front entry that this one replaces (parent)
//      The front entry that replaces this one (child)
// Yep, that's a quadruply-linked data structure.  Remember, you saw
// it here first.

class AnisoFrontEntry {
private:
  Vert *pVL, *pVR;
  Vert *pVLChild, *pVRChild;
  double dCellSize;
  bool qNeverAdvance, qAddedConvex;
  AnisoFrontEntry *pAFELeft, *pAFERight, *pAFEPrev, *pAFENext;
  // Disallow these, for now.  They aren't safe because of the linked
  // data structure: reciprocity is lost.
  AnisoFrontEntry(const AnisoFrontEntry&) {assert(0);}
public:
  // Dangerous to actually use this, but required for some containers...
  AnisoFrontEntry& operator=(const AnisoFrontEntry&) {assert(0); return(*this);}
  // Need a default constructor for container classes.
  AnisoFrontEntry() :
    pVL(pVInvalidVert), pVR(pVInvalidVert), pVLChild(pVInvalidVert),
    pVRChild(pVInvalidVert), dCellSize(0), qNeverAdvance(false),
    qAddedConvex(false),
    pAFELeft(pAFEInvalid), pAFERight(pAFEInvalid),
    pAFEPrev(pAFEInvalid), pAFENext(pAFEInvalid)
    {}
  // The real constructor that we'd like to be able to use, but may
  // never get to.
  AnisoFrontEntry(Vert * const pVLIn, Vert * const pVRIn,
	     AnisoFrontEntry * const pAFEPrevious = pAFEInvalid) :
    pVL(pVLIn), pVR(pVRIn), pVLChild(pVInvalidVert), pVRChild(pVInvalidVert),
    dCellSize(0), qNeverAdvance(false), qAddedConvex(false),
    pAFELeft(pAFEInvalid), pAFERight(pAFEInvalid), pAFEPrev(pAFEPrevious),
    pAFENext(pAFEInvalid)
    {
      assert(pVLIn->qValid());
      assert(pVRIn->qValid());
    }
  // Does the assignment tasks of the useful constructor, and also
  // assigns to empty objects that the default constructor has made.
  void vAssign(Vert * const pVLIn, Vert * const pVRIn,
	       AnisoFrontEntry * const pAFEPrevious = pAFEInvalid);

  // Data setting functions
  void vSetLeftNeighbor(AnisoFrontEntry * const pAFE)
    { assert(pAFE->qValid()); pAFELeft = pAFE; }
  void vSetRightNeighbor(AnisoFrontEntry * const pAFE)
    { assert(pAFE->qValid()); pAFERight = pAFE; }
  void vClearLeftNeighbor() {pAFELeft = pAFEInvalid;}
  void vClearRightNeighbor() {pAFERight = pAFEInvalid;}
  void vSetChild(AnisoFrontEntry * const pAFE)
    { assert(pAFE->qValid()); pAFENext = pAFE; }
  void vSetParent(AnisoFrontEntry * const pAFE)
    { assert(pAFE->qValid()); pAFEPrev = pAFE; }
  void vSetLeftVert(Vert * const pVLIn)
    { assert(pVLIn->qValid()); pVL = pVLIn; }
  void vSetRightVert(Vert * const pVRIn)
    { assert(pVRIn->qValid()); pVR = pVRIn; }
  void vSetLeftChildVert(Vert * const pVLCIn)
    { assert(pVLCIn->qValid()); pVLChild = pVLCIn; }
  void vSetRightChildVert(Vert * const pVRCIn)
    { assert(pVRCIn->qValid()); pVRChild = pVRCIn; }
  // Access functions
  AnisoFrontEntry * pAFELeftNeighbor()  const { return pAFELeft; }
  AnisoFrontEntry * pAFERightNeighbor() const { return pAFERight; }
  AnisoFrontEntry * pAFEChild()         const { return pAFENext; }
  AnisoFrontEntry * pAFEParent()        const { return pAFEPrev; }
  Vert * pVLeft() const { return pVL; }
  Vert * pVRight() const { return pVR; }
  Vert * pVLeftChild() const { return pVLChild; }
  Vert * pVRightChild() const { return pVRChild; }
  Vert * pVVert(const int iV) const
    {
      assert(iV == 0 || iV == 1);
      return ((iV == 0) ? pVL : pVR);
    }
  void vUnitNormal(double adNorm[2])
    {
      adNorm[0] = - pVR->dY() + pVL->dY();
      adNorm[1] = + pVR->dX() - pVL->dX();
      vNORMALIZE2D(adNorm);
    }
  void vLeftMarchingDirection(double adDir[2]);
  void vRightMarchingDirection(double adDir[2]);
  void vMarkNonAdvancing() {qNeverAdvance = true;}
  bool qAdvanceFromHere() const {return !qNeverAdvance;}
  void vMarkAddedConvex() {qAddedConvex = true;}
  bool qAddedInConvexCorner() const {return qAddedConvex;}
  bool qNullEntry() const
    {
      return !(pVL->qValid() && pVR->qValid());
    }
  bool qValid() const;
  bool qDegenerate() const {return pVL == pVR;}
  void vSetSize(const double dArea)
    {
      assert(dArea > 0);
      dCellSize = dArea;
    }
  double dSize() const {return dCellSize;}
  double dLength() const {return dDIST2D(pVL->adCoords(), pVR->adCoords());}

  friend void vMergeFE_2for1(AnisoFrontEntry* const pAFELeft,
			     AnisoFrontEntry* const pAFERight,
			     AnisoFrontEntry* const pAFEMerged);
  friend void vMergeFE_3for2(AnisoFrontEntry* const pAFELeft,
			     AnisoFrontEntry* const pAFEMiddle,
			     AnisoFrontEntry* const pAFERight,
			     Vert* const pVNew,
			     AnisoFrontEntry* const pAFEMergedLeft,
			     AnisoFrontEntry* const pAFEMergedRight);
};

#endif
