#ifndef D4TESS_H
#define D4TESS_H

#include <cassert>
#include <vector>
#include <set>
#include <iosfwd>
using namespace std;

#include <point.h>

#include <d4tri.h>

#include <virtualtetrahedron.h>
#include <d4minoperator.h>

#include <simplexface.h>

#include <d4fan.h>
#include <typedefs.h>

typedef point4<double> pt4;



//
//  Brief:  Tetrahedtron tessellation  
//
class d4tess
{
public:

  // For each point x y z are position and w is the field value.
  // Vector of points.  pt[0] is a null or no point.
  vector<pt4> pt;

  // Vector of simplexes, 
  // Note: vi[0] is a null or no simplex.
  vector<d4tri> vi;



  // Current Pointer.
  uint cp;
  // Current Orientation and is the virtual simplex(vs). 
  virtualtetrahedron vs;

  d4fan fan;

  // Upon insertion of a new primitive shape, it is minimized
  //   with the existing mesh.  This is a pointer to the binary operator.
  d4minoperator* minimizer;

  // Add a simplex 
  void viadd
  ( 
    uintc v0, uintc v1, uintc v2, uintc v3, 
    uintc n0=0, uintc n1=0, uintc n2=0, uintc n3=0
  );

  // Deletes the previous minimizer.
  void minimizerSet( d4minoperator* m);

  // The current virtual tetrahedron's points.
  // The first three points define the inner base in a clockwise ordering.
  // P3 is above the base. P2 is where the base triangle is pointing.
  void getpoints( pt4 & P0, pt4 & P1, pt4 & P2, pt4 & P3 ) const;

  // Move to the neighbouring simplex relative to vs.
  boolc tetmoveleft();
  // Move to the neighbouring simplex relative to vs.
  boolc tetmoveright();
  // Move to the neighbouring simplex relative to vs.
  boolc tetmovedown();

  // Orient the base triangle of vs to the boundary.
  boolc boundaryorient();
  // Assuming base of vs on the boundary, move down
  void surfacedown();
  // Assuming base of vs on the boundary, move left 
  void surfaceleft();
  // Assuming base of vs on the boundary, move right 
  void surfaceright();
  // Assuming base of vs on the boundary, is the point k
  //   viewable from the base face?
  boolc surfaceviewable(uintc k) const;

  // Get the current cp orientation as a cp and face pair.
  simplexface const cpsimplexface() const;

  // Get the current simplex.
  d4tri const & cpsimplex() const  
   { assert((cp!=0) && (cp<vi.size())); return vi[cp]; }

  // Greedy search minimizing towards point p in the mesh.
  boolc searchinsidemesh( uint & viewableface, uintc p );

  // One move - greedy.
  boolc move_terminated
  (
    bool & insidesimplex,
    uint & viewableface,
    uintc p
  );

  // Can we rotate about the vs base?
  boolc rotateaboutaxis(uint & steps);

  // Add an existing point to mesh creating new simplexes
  void addpoint(uintc k);

 
  ostream & print(ostream & os) const;

  // Error checking code.
  boolc valid() const;
  boolc valid(uintc k) const;
  boolc debugcheck() const;

  // Constructor - sets the maximum element size.
  d4tess( uintc arrayMax );

  // Destructor
  ~d4tess();

  // Reset the mesh.
  void reset();

  // Uses the first points build the first simplex, 
  //   assumes the points can form a simplex.
  void initialize();

  // Are the simplexes adjacent?
  boolc isconnected(uintc a, uintc b) const; 
  // Are the simplexes adjacent and together convex?
  boolc isconvex(uintc a, uintc b) const;


 // Binary operation transforming two adjacent simplexes 
  //   to an arrangement of three if possible.
  boolc tet2to3(uintc a, uintc b);
  boolc tet2to3_(uintc k1, uintc k2);


  // Transform virtual tetrahedron and neighbour at base.
  boolc tet2to3();
  // The base of the virtual triangle needs to be aligned to
  //   the intersecting axis of the three tetrahedrons.
  boolc tet2to3Inverse();


private:

  // Split the cp with the point k.
  void split( uintc k );

  void debugprinttet(uintc k) const;

  void infiniteRecursion();

};

ostream & operator << (ostream& os, d4tess const & x);


#endif



