#ifdef CGAL_USE_QT

#include <list>
#include <vector>

namespace std
{
   template <class T, class A> class vector;
   template <class T, class A>
   ostream & operator << (ostream & o, const vector<T,A> & vec)
   {
      int n = vec.size();
      o << "[vector (" << n << " element" << (n==1 ? "):" : "s):");
      for (int i = 0; i < n; ++i)
	 o << (i==0 ? " " : ",") << "[" << i << "] " << vec[i];
      return o << "]";
   }
}

#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/intersections.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>

#include <CGAL/Timer.h>

using namespace CGAL;
using std::list;
using std::vector;

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;

/***** lexicographic ordering on the points *****/

namespace CGAL
{
   bool operator < (const Point & p, const Point & q)
   {
      if (p.y() > q.y())
	 return true;
      if (p.y() < q.y())
	 return false;
      if (p.x() < q.x())
	 return true;
      return false;
   }
}

/***** Algorithm *****/

vector<int> calc_number_of_faces (const list<Point> & pts, Planar_map & subdiv)
{
   return vector<int> (pts.size()+1);
}

/***** dcel layer *****/

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

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

   *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();
}

/***** point layer *****/

class PointLayer : public Qt_widget_layer
{
      void draw();
   public:
      list<Point> points;

      PointLayer()
      {
	 for (int i = 0; i < 15; i++)
	 {
	    double phi = 2*i*M_PI/15;
	    points.push_back (Point(cos(phi),sin(phi)));
	 }
      }
};

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

   *widget << BLUE;
   for (list<Point>::const_iterator p = points.begin(); p != points.end(); ++p)
      *widget << *p;

   widget->unlock();
}

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

class DCELWindow : public QMainWindow
{
      Q_OBJECT

      Qt_widget *cgal_widget;
      Qt_widget_standard_toolbar *cgal_toolbar;
      DCELLayer dcellayer;
      PointLayer ptlayer;
      
   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(&dcellayer);
   cgal_widget->attach(&ptlayer);
   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();

   std::cout << "===================================================\n";
   std::cout << " Befehle: f -- Algorithmus aufrufen\n";
   std::cout << "          c -- Alle Punkte loeschen\n";
   std::cout << "          q -- Beenden\n";
   std::cout << "  mit Maus koennen neue Punkte hinzugefuegt werden\n";
   std::cout << "===================================================\n";
}

void DCELWindow::key_pressed (QKeyEvent* e)
{
   cgal_widget->clear();
   switch (e->key())
   {
      case Qt::Key_Q:
	 close();
	 break;
      case Qt::Key_C:
	 ptlayer.points.clear();
	 dcellayer.nicemap = Planar_map();
	 break;
      case Qt::Key_F:
	 std::cout << "=============================\n";
	 std::cout << "size of input: " << ptlayer.points.size() << " points\n";
	 std::cout << "calculating...\n";
	 Timer t;
	 t.start();
	 std::cout << "number of faces of size i:\n" << calc_number_of_faces(ptlayer.points,dcellayer.nicemap) << "\n";
	 t.stop();
	 std::cout << "size of output: " << dcellayer.nicemap.number_of_vertices() << " points and intersection points\n";
	 std::cout << "time: " << t.time() << "s\n";
	 std::cout << "=============================\n";
	 break;
   }
   cgal_widget->redraw();
}

void DCELWindow::mouse_pressed (QMouseEvent* e)
{
   ptlayer.points.push_back (Point (cgal_widget->x_real(e->x()), cgal_widget->y_real(e->y())));
   cgal_widget->redraw();
}

//moc_source_file : subdiv-window.C
#include "subdiv-window.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

