#ifndef LINECHOPPED_H
#define LINECHOPPED_H

#include <cassert>
#include <list>
#include <sstream>
using namespace std;

#include <line.h>
#include <mathlib.h>
#include <point.h>

/*!
\brief Maintain a linked list of chopped line segments.
*/
template< typename PT, typename PD >
class linechopped
{
public:

  /** The line. */
  line<PT,PD> ln;

  /** Chain segments. */
  list< point2<PD> > chain;

  /** Pass in an initial line segment. */
  linechopped
  ( 
    line<PT,PD> const & ln_,
    point2<PD> const & seg
  )
    : ln(ln_)
    { chain.push_back( seg ); }

  typedef typename list< point2<PD> >::iterator listiter;

  /** Split into two segments. The order is maintained.
      If the new element is inserted posnew then points to it
      and is before pos. */
  boolc split
  (
    listiter & posnew,
    listiter pos, 
    line<PT,PD> const & L2
  );

};


/*!
\brief Associate an index with a point.
*/
template< typename PT, typename INDX >
class pointindexed
{
public:

  /** The point. */
  PT pt;
  /** The index. */
  INDX index;

  /** Construct an indexed point. */
  pointindexed(PT const & pt_, INDX const index_)
    : pt(pt_), index(index_) {}

  /** Serialize this object by writing it out as a string. */
  operator string () const
    { string s( (stringc)pt ); s += " "; stringstream ss; 
     ss << index; return s + ss.str(); }

  /** Equal if components are equal. */
  boolc operator == ( pointindexed<PT,INDX> const & p2 ) const 
    { return (index==p2.index) && (pt==p2.pt); }
};

template< typename PT, typename INDX >
ostream & operator << (ostream & os, pointindexed<PT,INDX> const & p)
  { return os << (stringc)p; }


/*!
\brief Maintain a linked list of chopped line segments,
       each having an index.


*/
template< typename PT, typename PD, typename INDX >
class linechoppedindexed
{
public:

  /** The line. */
  line<PT,PD> ln;

  /** Chain segments. */
  list< pointindexed< point2<PD>, INDX> > chain;

  /** Pass in an initial line segment. */
  linechoppedindexed
  ( 
    line<PT,PD> const & ln_,
    pointindexed< point2<PD>, INDX > const & seg
  )
    : ln(ln_)
    { chain.push_back( seg ); }

  typedef typename list< pointindexed< point2<PD>, INDX > >::iterator 
    listiter;

  /** Split into two segments. The order is maintained. */
  boolc split
  (
    listiter & posnew,
    listiter pos, 
    line<PT,PD> const & L2
  );


};



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



template< typename PT, typename PD >
boolc linechopped<PT,PD>::split
(
  listiter & posnew,
  listiter pos, 
  line<PT,PD> const & L2
)
{
  bool res;
  point2<PD> t;
  res = solver<PD>::d2linearequ
    (t,ln.nml,L2.nml*((PD)-1.0), L2.pos - ln.pos);

  if (res==false)
    return false;

  PD t0(t[0]);

  if (t0<(*pos)[0])
    return false;

  if (t0>(*pos)[1])
    return false;

  // The line is being split.

  PD k0((*pos)[0]);
  (*pos)[0] = t0;
  
  posnew = chain.insert(pos,point2<PD>(k0,t0));

  return true;
}



template< typename PT, typename PD, typename INDX >
boolc linechoppedindexed<PT,PD,INDX>::split
(
  listiter & posnew,
  listiter pos, 
  line<PT,PD> const & L2
)
{
  bool res;
  point2<PD> t;
  res = solver<PD>::d2linearequ
    (t,ln.nml,L2.nml*((PD)-1.0), L2.pos - ln.pos);

  if (res==false)
    return false;

  PD t0(t[0]);

  if (t0<(*pos).pt[0])
    return false;

  if (t0>(*pos).pt[1])
    return false;

  PD k0((*pos).pt[0]);
  (*pos).pt[0] = t0;
  
  posnew = chain.insert(pos,pointindexed< point2<PD>, INDX >( point2<PD>(k0,t0),0));

  return true;
}







#endif



