#ifndef GR_Periodic
#define GR_Periodic

#include <map>

#include "GR_assert.h"
#include "GR_Classes.h"

// This class provides the glue to connect two faces at which a mesh
// should be periodic.
class Periodic {
  /// Copy construction disallowed
  Periodic(const Periodic&) {assert(0);}
  /// Operator= disallowed
  const Periodic& operator=(const Periodic&) {assert(0); return(*this);}
  /// Need to store pointers to two patches.
  BdryPatch *pBP1, *pBP2;
  /// Need to store a mapping between coords on one patch and on the other.
  double a2dRotation[3][3], adTranslation[3], dScaling;
  /// Need to know spatial dimension to apply mapping
  int iDim;
  /// Need to be able to map faces on patch 1 to faces on patch 2 and
  // vice versa.
  std::map<Face*, Face*> mFaceMap1to2, mFaceMap2to1;
 public:
  // Need a default constructor so that these things can be easily put
  // in arrays.
  Periodic();
  // This is the constructor to use when you can.
  Periodic(BdryPatch* const pPB1, BdryPatch* const pBP2);
  // Nothing needs to be done at destruct time.
  ~Periodic() {}
  // If you use the default constructor, you'd better be able to set
  // data afterwards.
  void vSetPatches(BdryPatch* const pPB1_In, BdryPatch* const pBP2_In);

  BdryPatch* pBPPatch(const int i) const {
    assert(i == 0 || i == 1);
    return (i == 0 ? pBP1 : pBP2);
  }
  // Given one of the paired patches, return the other.
  const BdryPatch* pBPOtherPatch(const BdryPatch* pBP) const;
  // Given a location on one of the paired patches, find the analog on
  // the other side.
  void vPeriodicLocation(const double adLocSrc[], const BdryPatch* const pBP,
			 double adLocComp[]) const;
  
  // Identify a face as falling on a periodic bdry patch
  void vAddFace(const BdryPatch* pBP, Face* pF);
  // Remove a face from a periodic bdry patch
  void vRemoveFace(const BdryPatch* pBP, Face* pF);
  // Find the face on the other bdry patch corresponding to this one
  const Face* pFFaceOpposite(const BdryPatch* pBP, Face* pF) const;
  // Get rid of all existing face data; useful when that data has been
  // rendered obsolete, for example during a purge.
  void vClearFaceData()
    { mFaceMap1to2.clear(); mFaceMap2to1.clear(); }
};

#endif
