// Vorosweep - Copyright (C) 2010-2014 T. Mouton
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <thibaud.mouton@gmail.com>.

#include <set>
#include <list>
#include <vector>
#include <stack>
#include <map>
#include "sweepobject.h"
#include <geom.h>

#ifndef _FRONTLINE_INCLUDE
#define _FRONTLINE_INCLUDE

namespace vorosweep
{
class Front;
class FrontLine;
class Polygon;

class FrontLine
{
private :
  SweepFacet *owner;
  std::list<Front*> frt;
  std::list<Polygon*> plist;
  std::list<Front *>::iterator itfr;
//     std::vector<SweepEdge *> pgse[2];
  int active_front;
public :
  FrontLine ( SweepFacet *sf, SweepEdge *s0, SweepEdge *s1 );
  inline SweepFacet *get_owner()
  {
    return owner;
  }
  inline SweepEdge *get_initial_sweepedge ( int i )
  {
    return owner->get_original_sweepedge ( i );
  }
  inline double *get_dir()
  {
    return owner->get_dir2d();
  }
  inline std::list<Polygon *> &get_polygons ( )
  {
    return plist;
  }
  inline int get_polygon_size ( )
  {
    return plist.size();
  }
  inline int is_active()
  {
    return ( active_front > 0 );
  }
  int seek_front ( Front *fr );
  Front *front_merge ( Front *fr0, Front *fr1 );
  void trigger ( Front *fr, SweepEdge *se );
  void set_edges ( std::list<SweepEdge *> nlist );
  int next_crash ( SweepEdge *se, double *pt );
  Front *get_including_front ( double *pos, double time );
  int valid_future_event ( double *pt );
  int valid_event ( double *pt, double time );
  void insert_edges ( SweepEdge *s0, SweepEdge *s1, double *pos, double time );
  void close_front ( Front *fr );
  void erase_front ( Front *fr );
  void substitute_front_children ( Front *fr );
  void update_sweepedge ( SweepEdge *se, SweepEdge *nse );
  void update_current ( double time );
  void generate_polygon_list ( );
  void print();
};

class Front
{
public:
  static int prev[2];
  static int next[2];
  enum frtrait {PRIMARY, MERGED, SPLITTED};
  enum frstatus {OPEN, CLOSED};
public:
  FrontLine *fl;
  Polygon *pol;
  Front *parent[2];
  Front *child[2];
  SweepEdge *cse[2];
  std::list<SweepEdge *>::iterator ite;
  frtrait trait;
  frstatus state;
public:
  Front ( FrontLine *line );
  inline void set_children ( Front *c0, Front *c1 )
  {
    child[0] = c0;
    child[0]->parent[0] = this;
    child[1] = c1;
    child[1]->parent[0] = this;
    trait = Front::SPLITTED;
  }
  inline void set_polygon ( Polygon *p )
  {
    pol = p;
  }
  inline Polygon *get_polygon ( )
  {
    return pol;
  }
  inline void set_parents ( Front *p0, Front *p1 )
  {
    p0->child[0] = this;
    parent[0] = p0;
    p1->child[0] = this;
    parent[1] = p1;
    trait = Front::MERGED;
  }
  inline SweepFacet *get_owner()
  {
    return fl->get_owner();
  }
  inline FrontLine *get_frontline()
  {
    return fl;
  }
  inline SweepEdge *get_sweepedge ( int i )
  {
    return cse[i];
  }
  void update_sweepedge ( int i, SweepEdge *nse )
  {
    dbgprintf ( 2, "front %p : updating sweepedge %d : old %p, new %p\n", this, i, get_sweepedge ( i ), nse );
    nse->set_front ( Front::next[i], this );
  }
  inline int isopen ( )
  {
    return ( state == Front::OPEN );
  }
  inline void close ( )
  {
    state = Front::CLOSED;
  }
  int inside ( double *pt, double t );
  void split ( SweepEdge *s0, SweepEdge *s1 );
  void update_current ( double time );
  int self_check ();
  void print ( );
};

class Polygon
{
private :
  std::list<Point *> vlist;
  std::list<SweepEdge *> elist;
public :
  Polygon ( Front *fr, SweepEdge *s0, SweepEdge *s1 );
  inline void insert_edge ( Front *fr, int position, SweepEdge *nse )
  {
    fr->ite = elist.insert ( fr->ite, nse );
    if ( position == 0 )
      fr->ite++;
  }
  inline void insert_edges ( Front *fr, SweepEdge *s0, SweepEdge *s1 )
  {
    fr->ite = elist.insert ( fr->ite, s0 );
    fr->ite++;
    fr->ite = elist.insert ( fr->ite, s1 );
    fr->ite++;
  }
  inline void remove_hole ( Front *fr0, Front *fr1 ) // should check this function
  {
    dbgprintf ( 2, "--> removing hole on polygon\n" );
    for ( std::list<SweepEdge*>::iterator ite = fr0->ite; ite != fr1->ite; /*ite++*/ )
    {
      ASSERT_ERROR((*ite) != NULL, "iterator point to NULL sweepedge\n");
      ite = elist.erase ( ite );
//       if (!(*ite))
//         return;
    }
  }
  inline void seek_front ( Front *fr, SweepEdge *se )
  {
    std::list<SweepEdge *>::iterator ite;
    for ( ite = elist.begin(); ite != elist.end(); ite++ )
    {
      if ( *ite == se )
      {
        fr->ite = ite;
        return;
      }
    }
    ASSERT_ERROR(0, "a problem occured while seeking front\n");
  }
  inline std::list<Point *> &get_points ( )
  {
    return vlist;
  }
  inline int get_point_size ( )
  {
    return vlist.size();
  }
  inline std::list<SweepEdge *> &get_edges ( )
  {
    return elist;
  }
  inline int get_edge_size ( )
  {
    return elist.size();
  }
  void generate_point_list ( );
  void merge_with ( Polygon *mpol, Point* pt );
};



};

#endif
