#ifdef CGAL_USE_QT

#include <list>
#include <qapplication.h>
#include <qmainwindow.h>
#include <CGAL/Cartesian.h>
#include <CGAL/Gmpq.h>
#include <CGAL/IO/Qt_widget.h>
#include <CGAL/IO/Qt_widget_layer.h>
#include <CGAL/IO/Qt_widget_standard_toolbar.h>

#include <CGAL/Pm_default_dcel.h>
#include <CGAL/Pm_segment_traits_2.h>
#include <CGAL/Planar_map_2.h>
#include <CGAL/IO/Pm_drawer.h>
#include <CGAL/IO/draw_pm.h>
#include <CGAL/IO/Pm_iostream.h>

using namespace CGAL;

typedef Gmpq number;
typedef Cartesian<number> K;

typedef Pm_segment_traits_2<K> Pm_traits;
typedef Pm_traits::Point_2 Point;
typedef Pm_traits::X_monotone_curve_2 Segment;
typedef Pm_default_dcel<Pm_traits> DCEL;

typedef Planar_map_2<DCEL,Pm_traits> Planar_map;

/***** working with the Planar_map *****/

void report_holes (const Planar_map & graph, const Point & p)
{
   Planar_map::Locate_type target;
   Planar_map::Halfedge_const_handle edge = graph.locate (p, target);
   switch (target)
   {
      case Planar_map::VERTEX:
	 std::cout << "point is on vertex " << edge->target()->point() << "\n";
	 break;
      case Planar_map::EDGE:
	 std::cout << "point is on edge " << edge->curve() << "\n";
	 break;
      case Planar_map::FACE:
	 std::cout << "point is on a face; traversing holes:\n";
	 for (Planar_map::Holes_const_iterator holesit = edge->face()->holes_begin(); holesit != edge->face()->holes_end(); ++holesit)
	    std::cout << "  -> " << (*holesit)->curve() << "\n";
	 break;
      case Planar_map::UNBOUNDED_FACE:
      default:
	 std::cout << "\"can someone help me, i think that i'm lost here\"\n";
	 break;
   }
}

void shoot_up (const Planar_map & graph, const Point & p)
{
   Planar_map::Locate_type target;
   Planar_map::Halfedge_const_handle edge = graph.vertical_ray_shoot (p, target, true);
   switch (target)
   {
      case Planar_map::VERTEX:
	 std::cout << "hit a vertex on edge: " << edge->curve() << "\n";
	 break;
      case Planar_map::EDGE:
	 std::cout << "hit an edge: " << edge->curve() << "\n";
	 break;
      case Planar_map::UNBOUNDED_FACE:
	 std::cout << "didn't hit anything...\n";
	 break;
      default:
	 std::cout << "\"can someone help me, i think that i'm lost here\"\n";
	 break;
   }
}

void shoot_down (const Planar_map & graph, const Point & p)
{
   Planar_map::Locate_type target;
   Planar_map::Halfedge_const_handle edge = graph.vertical_ray_shoot (p, target, false);
   switch (target)
   {
      case Planar_map::VERTEX:
	 std::cout << "hit a vertex on edge: " << edge->curve() << "\n";
	 break;
      case Planar_map::EDGE:
	 std::cout << "hit an edge: " << edge->curve() << "\n";
	 break;
      case Planar_map::UNBOUNDED_FACE:
	 std::cout << "didn't hit anything...\n";
	 break;
      default:
	 std::cout << "\"can someone help me, i think that i'm lost here\"\n";
	 break;
   }
}

void report_statistics (const Planar_map & graph)
{
   std::cout << "graph "
	     << (graph.is_valid() ? "is" : "is not") << " valid and contains "
	     << graph.number_of_vertices() << " vertices, "
	     << graph.number_of_halfedges() << " halfedges and "
	     << graph.number_of_faces() << " faces\n";
}


/***** one layer *****/

class DCELLayer : public Qt_widget_layer
{
      void draw();
   public:
      Point p;
      Planar_map nicemap;

      /* init the Planar_map */
      DCELLayer ()
      {
	 Point v1(0,0);
	 Point v2(0,1);
	 Point v3(1,0);
	 Point v4(-0.5,0.5);
	 Point v5(-1,0);
	 Point v6(-0.5,-0.5);
	 Point v7(0.5,-0.25);
	 Point h1(-0.1,-0.1);
	 Point h2(-0.2,-0.1);
	 Point h3(-0.1,-0.2);
	 Point h4(-0.5,0.1);
	 Point h5(-0.4,0.2);
	 Point h6(-0.4,0);
 
	 nicemap.insert (Segment(v1,v2));
	 nicemap.insert (Segment(v2,v3));
	 nicemap.insert (Segment(v3,v1));
	 nicemap.insert (Segment(v1,v4));
	 nicemap.insert (Segment(v4,v5));
	 nicemap.insert (Segment(v5,v6));
	 nicemap.insert (Segment(v6,v7));
	 nicemap.insert (Segment(v7,v1));
	 nicemap.insert (Segment(v7,v3));
	 nicemap.insert (Segment(h1,h2));
	 nicemap.insert (Segment(h2,h3));
	 nicemap.insert (Segment(h3,h1));
	 nicemap.insert (Segment(h4,h5));
	 nicemap.insert (Segment(h5,h6));
	 nicemap.insert (Segment(h6,h4));
      }
};

void DCELLayer::draw()
{
   widget->lock();

   *widget << BLUE << p;

   *widget << GREEN;
   Pm_drawer<Planar_map,Qt_widget> drawer (*widget);
   draw_pm<Planar_map,Pm_drawer<Planar_map,Qt_widget>,Qt_widget> (nicemap, drawer, *widget);

   *widget << RED;
   drawer.draw_vertices (nicemap.vertices_begin(), nicemap.vertices_end());

   widget->unlock();
}

/***** main window *****/

class DCELWindow : public QMainWindow
{
      Q_OBJECT

      Qt_widget *cgal_widget;
      Qt_widget_standard_toolbar *cgal_toolbar;
      DCELLayer onlylayer;
      
   public:
      DCELWindow(int width=600, int height=600, double xleft=-1.1, double xright=1.1, double ylower=-1.1, double yupper=1.1);

   private slots:
      void mouse_pressed (QMouseEvent* e);
      void key_pressed (QKeyEvent* e);
};

DCELWindow::DCELWindow (int x, int y, double xleft, double xright, double ylower, double yupper)
{
   cgal_widget = new Qt_widget(this);
   cgal_widget->resize(x,y);
   cgal_widget->set_window (xleft, xright, ylower, yupper);
   cgal_toolbar = new CGAL::Qt_widget_standard_toolbar (cgal_widget, this, "DCEL Window Toolbar");
   cgal_widget->attach(&onlylayer);
   connect (cgal_widget, SIGNAL(s_keyPressEvent(QKeyEvent*)), this, SLOT(key_pressed(QKeyEvent*)));
   connect (cgal_widget, SIGNAL(s_mousePressEvent(QMouseEvent*)), this, SLOT(mouse_pressed(QMouseEvent*)));
   setCentralWidget (cgal_widget);
   cgal_widget->grabKeyboard();
}

void DCELWindow::key_pressed (QKeyEvent* e)
{
   cgal_widget->clear();
   switch (e->key())
   {
      case Qt::Key_Q:
	 close();
	 break;
      case Qt::Key_Up:
	 shoot_up (onlylayer.nicemap, onlylayer.p);
	 break;
      case Qt::Key_Down:
	 shoot_down (onlylayer.nicemap, onlylayer.p);
	 break;
      case Qt::Key_H:
	 report_holes (onlylayer.nicemap, onlylayer.p);
	 break;
      case Qt::Key_S:
	 report_statistics (onlylayer.nicemap);
	 break;
   }
   cgal_widget->redraw();
}

void DCELWindow::mouse_pressed (QMouseEvent* e)
{
   onlylayer.p = Point (cgal_widget->x_real(e->x()), cgal_widget->y_real(e->y()));
   cgal_widget->redraw();
}

//moc_source_file : dcel-plain.C
#include "dcel-plain.moc"

/***** main() *****/

int main (int argc, char** argv)
{
   QApplication app(argc,argv);
   DCELWindow mainwindow;
   app.setMainWidget (&mainwindow);
   mainwindow.show();

   return app.exec();
}

#else

#include <iostream>

int main ()
{
   std::cout << "Sorry, this program needs QT...";
   std::cout << std::endl;
   return 0;
}

#endif // CGAL_USE_QT

