#ifndef PNLINK_H
#define PNLINK_H

#include <typedefs.h>

/*!
\brief Link to a point and a neighbor.

This can be used to represent a polygon
 as a circular list with each point having
 a link to the on the face of this and the
 next point.

By definition a null link has a point plink with
 0 value meaning that the link is not pointing to
 any point.

<TODO> Provide memory management by overloading
 new and delete for this class.
*/
template< typename Indx >
class pnlink
{
public:

  typedef Indx const Indxc;

  /** Point link. */
  Indx plink;

  /** Neighbor link. */
  Indx nlink;

  /** Next element in circular list. */
  pnlink<Indx> * next;

  /** Possibly partially constructed. */
  pnlink(Indxc plink_, Indxc nlink_)
    : plink(plink_), nlink(nlink_), next(this) {}
  /** Fully constructed. */
  pnlink(Indxc plink_, Indxc nlink_, pnlink<Indx> * next_)
    : plink(plink_), nlink(nlink_), next(next_) {}

  /** Construct two consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc n0, Indxc n1);
  /** Construct three consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc n0, Indxc n1, Indxc n2);
  /** Construct four consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc p3, 
         Indxc n0, Indxc n1, Indxc n2, Indxc n3);
  /** Construct five consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, 
         Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4);
  /** Construct six consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5,
         Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5);
  /** Construct seven consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5, Indxc p6,
         Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5, Indxc n6);
  /** Construct eight consecutive links. */
  pnlink(Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5, Indxc p6, Indxc p7,
         Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5, Indxc n6, Indxc n7);

  /** Unconstructed state. */
  pnlink()
    : plink(0), nlink(0), next(0) {}

  /** Iterate around the ring to find the link with the point. */
  pnlink<Indx> * piInverse( Indx gpt ) const;
  /** Iterate around the ring to find the link with the neighbor. */
  pnlink<Indx> * niInverse( Indx neib );

  /** Insert after this link. */
  void insert( pnlink<Indx> & next_)
    { next_.next = next; next = & next_; }
  /** Insert a new link after this link. */
  void addafterself(Indxc p0, Indxc n0)
    { next = new pnlink(p0,n0,this->next); }

  /** Find the point ptindx and add new link copying its neighbor. */
  boolc add(Indxc ptindx, Indxc p0);

  /** Is the link null? */
  boolc isnull() const
    { return plink==0; }
};


/*!
\brief Iterate about pnlink<Index>.

The for loop tests before entry so here the do while loop
 is used instead.

\par Example
\verbatim
    pnlinkiterconst<Indx> k(tess.vi[i].start);
    k.reset();
    do
    {
       ...
       ++k;
    } while (!k);
\endverbatim
*/
template< typename Indx >
class pnlinkiter
{
public:

  typedef pnlink<Indx> link;

  /** The start of the circular loop. */
  link * start;
  /** The current link. */
  link * current;

  /** Construct with a definite link. */
  pnlinkiter(  link * _start )
    : start(_start) {}

  /** Reset the iterator to the start. */
  void reset() 
    { assert(start!=0); current=start; }
  /** Move to the next link. */
  void operator ++ () 
    { assert(current!=0); current = current->next; }
  /** Are there any more links to iterate over? */
  boolc operator ! () const
    { return current != start; }

  /** Access the current link. */
  link * operator () () const 
    { return current; }
  /** Access the current link. */
  link * operator -> () const
    { return current; }
};





/*!
\brief Iterate about pnlink<Index> const.
*/
template< typename Indx >
class pnlinkiterconst
{
public:

  typedef pnlink<Indx> const link;

  /** The start of the circular loop. */
  link * start;
  /** The current link. */
  link * current;

  /** Construct with a definite link. */
  pnlinkiterconst(  link * _start )
    : start(_start) {}

  /** Reset the iterator to the start. */
  void reset() 
    { assert(start!=0); current=start; }
  /** Move to the next link. */
  void operator ++ () 
    { assert(current!=0); current = current->next; }
  /** Are there any more links to iterate over? */
  boolc operator ! () const
    { return current != start; }

  /** Access the current link. */
  link * operator () () const 
    { return current; }
  /** Access the current link. */
  link * operator -> () const
    { return current; }
};


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

template< typename Indx >
boolc pnlink<Indx>::add(Indxc ptindx, Indxc p0)
{
  pnlink<Indx> * pl = piInverse(ptindx);
  if (pl==0)
    return false;

  Indx n0 = pl->nlink;
  pl->addafterself(p0,n0);

  return true;
}

template< typename Indx >
pnlink<Indx> * pnlink<Indx>::piInverse( Indx gpt ) const
{
  pnlinkiter<Indx> iter(this);
  for ( iter.reset(); !iter; ++iter )
  {
    if (iter->plink==gpt)
      return iter();
  }

  return 0;
}

template< typename Indx >
pnlink<Indx> * pnlink<Indx>::niInverse( Indx neib ) 
{
  pnlinkiter<Indx> iter(this);
  for ( iter.reset(); !iter; ++iter )
  {
    if (iter->nlink==neib)
      return iter();
  }

  return 0;
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc n0, Indxc n1
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc n0, Indxc n1, Indxc n2
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p2,n2);
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc n0, Indxc n1, Indxc n2, 
  Indxc n3
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p3,n3);
  addafterself(p2,n2);
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc n0, Indxc n1, 
  Indxc n2, Indxc n3, Indxc n4
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p4,n4);
  addafterself(p3,n3);
  addafterself(p2,n2);
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5, Indxc n0, 
  Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p5,n5);
  addafterself(p4,n4);
  addafterself(p3,n3);
  addafterself(p2,n2);
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5, Indxc p6, 
  Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5, Indxc n6
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p6,n6);
  addafterself(p5,n5);
  addafterself(p4,n4);
  addafterself(p3,n3);
  addafterself(p2,n2);
  addafterself(p1,n1);
}

template< typename Indx >
pnlink<Indx>::pnlink
(
  Indxc p0, Indxc p1, Indxc p2, Indxc p3, Indxc p4, Indxc p5, Indxc p6, Indxc p7,
  Indxc n0, Indxc n1, Indxc n2, Indxc n3, Indxc n4, Indxc n5, Indxc n6, Indxc n7
)
{
  plink = p0;
  nlink = n0;
  next = this;
  addafterself(p7,n7);
  addafterself(p6,n6);
  addafterself(p5,n5);
  addafterself(p4,n4);
  addafterself(p3,n3);
  addafterself(p2,n2);
  addafterself(p1,n1);
}



#endif



