#ifndef D4TRI_H
#define D4TRI_H

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

#include <typedefs.h>

/*!
\brief:  A linked tetrahedron data structure.
*/
class d4tri
{
public:

  // Indexes to points or verticies.
  uint pi[4];
  // Indexes to neighboring tetrahedrons.
  uint ni[4];
  // Get the local point index.
  uintc piInverse( uintc gpt ) const
  {
    assert(gpt!=0);

    if (pi[0]==gpt) return 0;
    if (pi[1]==gpt) return 1;
    if (pi[2]==gpt) return 2;
    if (pi[3]==gpt) return 3;

    assert(false);
    return 4; // Return crap.
  }
  uintc piInverse( bool& res, uintc neib ) const;
  // Get the local neighbour index.
  uintc niInverse( uintc neib ) const
  {  
    if (ni[0]==neib) return 0;
    if (ni[1]==neib) return 1;
    if (ni[2]==neib) return 2;
    if (ni[3]==neib) return 3;

    assert(false);
    return 4; // Return crap.
  }  
  uintc niInverse( bool& res, uintc neib ) const;



 


  // Default Constructor: all fields set to 0.
  d4tri();
  // Construct a tetrahedron.
  d4tri
  (
    uintc a, uintc b, uintc c, uintc d, 
    uintc na=0, uintc nb=0, uintc nc=0, uintc nd=0
  );
  // Construct this tetrahedron.
  void construct 
  (
    uintc a, uintc b, uintc c, uintc d,
    uintc na, uintc nb, uintc nc, uintc nd
  );

  // Returns anticlockwise triangle point indexes
  //   a,b,c are indexes from {0,1,2,3}
  void getanticlockwiseface( uint & a, uint & b, uint & c, uintc face) const;

  // Returns clockwise triangle point indexes
  //   a,b,c are indexes from {0,1,2,3}
  void getclockwiseface( uint & a, uint & b, uint & c, uintc face) const;

  // Query Functions

  // Is the tetrahedron part of the surface?
  boolc isonboundary() const;
  
  // Is the point a vertex of this tetrahedron?
  boolc isavertex( uintc gpt ) const;

  // Set all pointers to 0.
  void setnull();
  // Is this a tetrahedron? Are all the fields set to zero?
  boolc isnull() const;

  // Compare their points
  boolc hassamepoints(d4tri const & w) const;

  // Supportive functions that use the basic operations.

  // Modifiy a neighboring pointer. 
  void niReset( uintc from, uintc to )
    { ni[ niInverse(from) ] = to; }

  // Common operation of getting face from opposite point.
  uint & niFrompiInverse(uintc gpt)
    { return ni[ piInverse(gpt) ]; }

  // Possibly remove this function.
  //  a,b,c each have a value from { 0,1,2,3 }.
  //  find x which has the last remaining value.
//  void solvex(uint & x, uintc a, uintc b, uintc c) const;

  ostream & print(ostream& os) const;
private:

  // As a quick check to compare if two tets have the same points.
  uintc sumofpoints() const;
};

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

//   The Tetrahedron Data Structure
//
//   The tetrahedrons are doubly linked with each other.
//  
//   This class indexes into point and neighbor 
//   vectors with integers.
//
//   Support for constructing, querying and using the
//   data structure is given.
//
//   The perspective is that of the tetrahedron,
//   not the verticies or points, so algorithms
//   using this data structure can be clearer.

//
//   The points are anticlockwise with the 4th point 
//     comming out of the page.
//
//             pi[2]
//
//
//     pi[0]          pi[1]
//
//
//   The neibors are defined opposite to the
//   points. The neibors are the faces and point
//   to other tetrahedrons.
//
//   eg  ni[0] is pointing to the tetrahedron connected
//   to the opposite face of point pi[0], 0 indicates no
//   neibor.
//


#endif



