#include <CGAL/Cartesian.h>
#include <CGAL/Point_2.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/IO/Qt_widget_Delaunay_triangulation_2.h>
#include <CGAL/IO/Qt_widget.h>
#include <CGAL/IO/Qt_widget_layer.h>
#include <qapplication.h>

typedef CGAL::Cartesian<double>		    Rep;
typedef CGAL::Point_2<Rep>		    Point;
typedef CGAL::Circle_2<Rep>		    Circle;

typedef CGAL::Triangulation_vertex_base_with_info_2<CGAL::Color,Rep> Vb;
typedef CGAL::Triangulation_face_base_2<Rep> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> Tds;
typedef CGAL::Delaunay_triangulation_2<Rep,Tds> Delaunay;

typedef Delaunay::Vertex_handle             VertexH;
typedef Delaunay::Vertex_circulator         VCirculator;
typedef Delaunay::Finite_vertices_iterator  Viterator;


class Dist_order {
  const Delaunay *t;
  const Point *p;

public:
  Dist_order(const Delaunay *tr, const Point *po)
    : t(tr), p(po) {}

  bool operator()(VertexH v1, VertexH v2) const
  {
    return CGAL::compare_distance_to_point(*p, v1->point(), v2->point())
           == CGAL::SMALLER;
  }
};

typedef  std::set<VertexH, Dist_order> Queue;


/////////////////////////////////////////////////////////
//  The displayed objects are declared here as global variables.
//  The display code is the "draw" member function below.

Delaunay         dt;
Point            the_point = Point();

class My_layer : public CGAL::Qt_widget_layer {
  void draw() {
    *widget << CGAL::BLACK << dt << CGAL::PointSize(4);
    if (dt.number_of_vertices() < 1) return;

    Viterator vit = dt.finite_vertices_begin(), end = dt.finite_vertices_end();
    while (vit != end) {
      *widget << vit->info() << vit->point();
      ++vit;
    }

    if (the_point == Point() ) return;
    *widget << CGAL::PointSize(8) << CGAL::GREEN << the_point;

    Queue            queue(Dist_order(&dt, &the_point));
    Queue::iterator  all_neighbors;
    CGAL::Color      color_of_the_first;
    VertexH          v;

    queue.clear();
    queue.insert(dt.nearest_vertex(the_point));
    all_neighbors = queue.begin();
    v = *all_neighbors;

    color_of_the_first = v->info();
    *widget << CGAL::YELLOW
	    << Circle(the_point, CGAL::squared_distance(the_point,v->point()))
	    << v->info() << v->point();
    while ((*all_neighbors)->info() == color_of_the_first) {
      v = *all_neighbors;
      VCirculator circ = dt.incident_vertices(v), circDone = circ;
      do {
	if (!dt.is_infinite(circ)) queue.insert(circ);
	++circ;
      } while (circ != circDone);
      ++all_neighbors;
      if (all_neighbors == queue.end()) {
	std::cout<< "no neighbor "
		 << (color_of_the_first == CGAL::RED ? "blue !" : "red !")
		 << std::endl;
	return;
      }
    }
    v = *all_neighbors;
    *widget << CGAL::YELLOW
	    << Circle(the_point, CGAL::squared_distance(the_point, v->point()))
	    << v->info() << v->point();
  }
};

class My_window : public CGAL::Qt_widget {
public:
  My_window(int x, int y)
  {
    resize(x,y);
    attach(&layer);
  }
private:
  //this method is called when the user presses the mouse
  void mousePressEvent(QMouseEvent *e)
  {
    Qt_widget::mousePressEvent(e);
    VertexH v;

    /////////////////////////////////////////////////////////////
    //  HERE IS WHAT IS EXECUTED ON A MOUSE CLICK !
    //
    if (e->button() == Qt::LeftButton) {
      v = dt.insert(Point(x_real(e->x()), y_real(e->y())));
      v->info() = CGAL::RED;
      the_point = Point();
    }
    if (e->button() == Qt::MidButton) {
      v = dt.insert(Point(x_real(e->x()), y_real(e->y())));
      v->info() = CGAL::BLUE;
      the_point = Point();
    }
    if (e->button() == Qt::RightButton) {
      the_point = Point(x_real(e->x()), y_real(e->y()));
    }
    /////////////////////////////////////////////////////////////

    redraw();
  }
  My_layer layer;
};

int main( int argc, char **argv )
{
    QApplication app( argc, argv );
    My_window *W = new My_window(400, 400);
    app.setMainWidget(W);
    W->show();
    W->set_window(0, 400, 0, 400);
    return app.exec();
}
