#ifndef POLYTOPED2TESS_H
#define POLYTOPED2TESS_H

#include <typedefs.h>

template< typename VPOLY, typename VPTS >
class polytopeD2tess
{
public:

  /** Vector of polytopes indexes to the points. */
  VPOLY & vi;
  /** Vector of points. */
  VPTS & pts;

  /** Initialize the polytope vector and global points. */
  polytopeD2tess 
  (
    VPOLY & vi_,
    VPTS & pts_
  )
    : vi(vi_), pts(pts_) {}

  /** Test the k'th polytope. */
  boolc verify(uintc k) const;

  /** Test all the polytopes. */
  boolc verify() const;

  /** Add to the k'th polytope a new point. The neighbors link
      is also updated. */
  void addpoint( uintc k, uintc ptindex, uintc ptglobal );

  /** Print the tessellation. */
  void printvi() const;
};

//---------------------------------------------------------
// Implementation  

template< typename VPOLY, typename VPTS >
void polytopeD2tess<VPOLY,VPTS>::printvi() const
{
  for (uint i=1; i<vi.size(); ++i)
    cout << (string)vi[i] << endl;
}

template< typename VPOLY, typename VPTS >
boolc polytopeD2tess<VPOLY,VPTS>::verify() const
{
  uintc imax = vi.size();
  for (uint i=0; i<imax; ++i)
  {
    if (verify(i)==false)
      return false;
  }

  return true;
}

template< typename VPOLY, typename VPTS >
boolc polytopeD2tess<VPOLY,VPTS>::verify(uintc k) const
{
  polytopeD2linked const & x(vi[k]);
  if (x.isnull())
    return true;

  uintc sz = x.ni.size();
  assert(x.pi.size()==sz);
  if (x.pi.size()!=sz)
    return false;

  uint nicurrent;
  for (uint i=0; i<sz; ++i)
  {
    nicurrent=x.ni[i];
    if (nicurrent==0)
      continue;

    assert(nicurrent<vi.size());
    if ((nicurrent<vi.size())==false)
      return false;

    assert(vi[nicurrent].niInverseHas(k)==true);
    if (vi[nicurrent].niInverseHas(k)==false)
      return false;
  }

  return true;
}


template< typename VPOLY, typename VPTS >
void polytopeD2tess<VPOLY,VPTS>::addpoint
( 
  uintc k, 
  uintc ptindex, 
  uintc ptglobal 
)
{
  assert(k<vi.size());
  assert(ptindex<pts.size());
  assert(ptglobal<pts.size());

  polytopeD2linked & A(vi[k]);
  
//cout << SHOW(k) << endl;
//cout << SHOW(ptindex) << endl;
  uintc j = A.piInverse(ptindex);
  uintc neib = A.ni[j];
  uint i = (j+1) % A.pi.size(); 
//cout << SHOW(i) << endl;
//cout << SHOW(neib) << endl;
  // Has the polygon got a neighbor?
  if (neib!=0)
  {
    uintc ptindex2 = A.pi[i];
//cout << SHOW(ptindex2) << endl;
    polytopeD2linked & B(vi[neib]);
    B.addpoint(ptindex2,ptglobal);
  }

  A.addpoint(ptindex,ptglobal);
}


#endif


