#ifndef SIMPLEXD2LINKED_H
#define SIMPLEXD2LINKED_H

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

#include <typedefs.h>


/*
\brief A doubely linked triangle data structure.

This data structure has a mathematical perspective and
 is designed to support operations on the simplex 
 (triangle in 2D).

Operations with Inverse appended are the reverse of the original
 operators.  So pi[piInverse(10)] should yield 10

Winding or order of points was implied on the data structure
 although for most operations the operators are invariant to
 the order.  

There are two coordinate systems - the local ones accessing
 the arrays pi and ni and the global coordinate system which indexes
 points and triangles with integers.
*/
class simplexD2linked
{
public:

  /** Indexes to points or verticies. */
  uint pi[3];
  /** Indexes to neighboring simplexes. 
      If ni[k] is 0 this is a boundary/surface edge. */
  uint ni[3];

  /** Use global points as references to get the opposite 
      neighbor. */
  uintc nifrom( uintc gpt ) const
    { return ni[piInverse(gpt)]; }

  /** 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;

    assert(false);
    return 3; // Return crap.
  }
  /** Given the point does it belong to this simplex? */
  boolc piInverseHas( uintc gpt ) const
  {
    if (pi[0]==gpt) return true;
    if (pi[1]==gpt) return true;
    if (pi[2]==gpt) return true;

    return false;
  }

  /** Both find the point inverse and query if it exists. */
  uintc piInverse( bool& res, uintc gpt ) const
  {
    res=true;
    if (pi[0]==gpt) return 0;
    if (pi[1]==gpt) return 1;
    if (pi[2]==gpt) return 2;

    res=false;
    return 3; // Return crap.
  }

  /** 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;

    assert(false);
    return 3; // Return crap.
  }  
  /** Has the simplex got a pointer to neib? */
  boolc niInverseHas( uintc neib ) const
  {  
    if (ni[0]==neib) return true;
    if (ni[1]==neib) return true;
    if (ni[2]==neib) return true;

    return false; 
  }  
  /** Both find the inverse and query if it exists. */
  uintc niInverse( bool& res, uintc neib ) const
  {
    res=true;
    if (ni[0]==neib) return 0;
    if (ni[1]==neib) return 1;
    if (ni[2]==neib) return 2;

    res=false;
    return 3; // Return crap.
  }  



  /** Default Constructor: all fields set to 0. */
  simplexD2linked();
  /** Construct a triangle. */
  simplexD2linked
  (
    uintc a, uintc b, uintc c,
    uintc na=0, uintc nb=0, uintc nc=0
  );
  /** Construct this triangle. */
  void construct 
  (
    uintc a, uintc b, uintc c,
    uintc na, uintc nb, uintc nc
  );

  /** Returns anticlockwise point indexes
     a,b are indexes from <0,1,2>
     eg  face 1 identifies the face opposite the point 1 
     which is line form 2 to 0. */
  void getanticlockwiseface( uint & a, uint & b, uintc face) const;

  /** Returns clockwise point indexes
    a,b are indexes from <0,1,2> */
  void getclockwiseface( uint & a, uint & b, uintc face) const;

  // Query Functions

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

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


  // Supportive functions that use the basic operations.

  /** Change the link to point to another simplex. */
  void changelink( uintc from, uintc to )
    { ni[ niInverse(from) ] = to; }

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

  /** Do two triangles have the same points? 
      Assumes simplex has unique points, 
      so (1,1,2) is not compared with (2,2,1). */
  boolc operator == (simplexD2linked const & w) const;

  /** Write the object out. */
  operator string() const;
  /** Read the object in. */
  void serializeInverse(stringc & s);
  /** Write the object out. */
  ostream & print(ostream& os) const;
  /** Read the object in. */
  istream & serializeInverse(istream & is);
};

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

istream & operator >> (istream & is, simplexD2linked & x);





#endif



