#ifndef DEMO_TAB_H
#define DEMO_TAB_H

/*! demo_tab.h contain the definetion and implementation of 
 *  the demo tab classes and the tabs traits classes.       
 *  all the possible shared code is in Qt_widget_demo_tab where
 *  the differences is in the traits classes.
 */
#include <math.h>

#include <qrect.h>
#include <qcursor.h>
#include <qmessagebox.h> 
#include <qcolor.h>
#include <qpainter.h> 
#include <qpen.h>

#include "cgal_types.h"
#include "seg_notif.h"
#include "pol_notif.h"
#include "conic_notif.h"
#include <CGAL/IO/pixmaps/hand.xpm>
#include <CGAL/IO/pixmaps/holddown.xpm>
#include <CGAL/Polygon_2.h>
#include <CGAL/IO/Qt_widget_Polygon_2.h>

#include<vector>

/*! class Qt_widget_base_tab - inherits from CGAL::Qt_widget
 *  contain all data members that are not part of the traits 
 */
class Qt_widget_base_tab : public CGAL::Qt_widget
{
public:

  /*!
   */
  Qt_widget_base_tab(TraitsType  t , Strategy _straregy, QWidget *parent = 0,
                     int tab_number = 1 ) :
    CGAL::Qt_widget( parent ),
    current_state(0),
    
    index(tab_number),
    snap_mode(NONE),
    mode(INSERT),
    m_line_width(2),
    m_vertex_width(3),
    first_time(true),
    active(false),
    traits_type(t),
    bbox(CGAL::Bbox_2(-10, -10, 10, 10)),
    wasrepainted(true), 
    on_first(false),
    change_pm_color(false),
    snap(false),
    grid(false),
    conic_type(SEGMENT),
    cube_size(1),
    ray_shooting_direction(true),
    remove_org_curve(true),
    read_from_file(false),
    empty(true),
    first_time_merge(true),
    draw_vertex(true),
    fill_face_color(def_bg_color),
    strategy(_straregy)
  {
    static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(2) <<
      CGAL::BackgroundColor (CGAL::BLACK);
    set_window(0, 700, 0, 700);
   
    setMouseTracking(TRUE);
    
    colors[1] = Qt::blue;
    colors[2] = Qt::gray;
    colors[3] = Qt::green;
    colors[4] = Qt::cyan;
    colors[5] = Qt::magenta;
    colors[6] = Qt::darkRed;
    colors[7] = Qt::darkGreen;
    colors[8] = Qt::darkBlue;
    colors[9] = Qt::darkMagenta;
    colors[10] = Qt::darkCyan;
    colors[11] = Qt::yellow;

    pm_color = colors[index];
  }

  /*! Destructor */
  virtual ~Qt_widget_base_tab(){}
  
  /*! current_state - indecates when a tab state is changed */
  int current_state;

  /*! index - each tab has a uniqe index */
  int index;

  /*! pl_point - the point for point location */
  Coord_point pl_point;

  /*! snap_mode - current snap mode (none, grid or closest point)  */
  SnapMode snap_mode;

  /*! mode - current mode (insert,delete or point location) */
  Mode mode;

  /*! m_line_width - line width */
  int m_line_width;

  /*! m_vertex_width - vertex width */
  int m_vertex_width;

  /*! first_time - true when it is the first mouse click of the object */
  bool first_time;

  /*! active - true if the first point was inserted */
  bool active;

  /*! traits_type - the actual tab traits */
  TraitsType   traits_type;

  /*! bbox - bounding box */
  CGAL::Bbox_2 bbox;

  /*! for use of drag mode */
  int   first_x, first_y;
  int   x2, y2;
  bool    wasrepainted;
  bool    on_first;

  /*! array of colors */
  QColor colors[20];

  /*! planar map color */
  QColor pm_color;

  /*! flag to know that pm color has changed */
  bool change_pm_color;

  /*! snap flag */
  bool snap;

  /*! grid flag */
  bool grid;

  /*! conic insert type */
  ConicType conic_type;

  /*! grid cube size */
  int cube_size;

  /*! ray shooting direction */
  bool ray_shooting_direction; // true for up

  /*! remove all original curve or only a part */
  bool remove_org_curve;

  /*! pm read from file - need a spcial treatment */
  bool read_from_file;

  /*! true if pm is empty */
  bool empty;

  /*! true when it is the first time in merge mode */
  bool first_time_merge;

  /*! true when you want to draw all vertex, false if
   * only the intersecting vertex
   */
  bool draw_vertex;

  /*! the color for filling faces ( obtained by fill button) */
  QColor fill_face_color;

  /*! point location strategy */
  Strategy strategy;

  /*! get the color of the unbounded face (its the same as the background
   * color of the tab)
   */
  QColor unbounded_face_color() { return this->backgroundColor(); } 

  /*! set the colo of the unbounded face (its the same as the background
   * color of the tab)
   */
  void set_unbounded_face_color(QColor c) { this->setBackgroundColor(c); } 

  /*! increment current_state to inidicate that something has changed
   */
  void something_changed(){ current_state++ ; }
};


/*! check if  two segemnts are mergeable
 */
template<class Pm_point_2>
bool merge_segments_precondition(Pm_point_2 s, Pm_point_2 t, Pm_point_2 s1,
                                 Pm_point_2 t1 ,int s_degree , int t_degree)
{
  return
    //  cannot be the same curve as closest_curve
    (!((s1 == s && t1 == t) || (s1 == t && t1 == s)) && 
     // must be one shared point
     (s1 == s || t1 == t || s1 == t || t1 == s) && 
     (!(((s == s1 || s == t1) && s_degree != 2) ||
        // vertex degree must be exactly 2
        ((t == s1 || t == t1) && t_degree != 2))) && 
     ((s == s1 && ((t.x() < s.x() && t1.x() > s.x()) ||
                   (t.x() > s.x() && t1.x() < s.x()))) ||
      (s == t1 && ((t.x() < s.x() && s1.x() > s.x()) ||
                   (t.x() > s.x() && s1.x() < s.x()))) ||
      (t == s1 && ((t.x() < s.x() && t1.x() < t.x()) ||
                   (t.x() > s.x() && t1.x() > t.x()))) ||
      (t == t1 && ((t.x() < s.x() && s1.x() < t.x()) ||
                   // checking x-monotone
                   (t.x() > s.x() && s1.x() > t.x()))) || 
      // dealing with vertical curves
      ((s.x() == s1.x())&&( t.x() == t1.x()) && (s.x()==t.x()))));  
}

/*!
 */
template<class ColorsIterator>
QColor blend_colors(ColorsIterator begin_colors , ColorsIterator  end_colors)
{
  ColorsIterator clr_itr;
  int red = 0,
    green = 0,
    blue = 0,
    counter = 0; 

  QColor avg_color = def_bg_color; // the average color

  for(clr_itr = begin_colors ; clr_itr!= end_colors ; ++clr_itr)
  {
    QColor curr_color = *clr_itr;
    if( curr_color.isValid() && curr_color != def_bg_color)
    {
      red += curr_color.red();
      green += curr_color.green();
      blue += curr_color.blue();
      counter++;
    }
  }

  if( counter)  // make sure counter is not equal zero
    avg_color = QColor(red / counter , green / counter , blue / counter);

  return avg_color ; 
}


/*! template class Qt_widget_demo_tab gets a Tab_traits class as 
 *  a template parameter. all the Tab_traits classes must support
 *  a set of demands.
 */
template <class Tab_traits>
class Qt_widget_demo_tab : public Qt_widget_base_tab
{
private:
  typedef typename Tab_traits::Curves_list Curves_list;
  typedef typename Tab_traits::Curves_arr Curves_arr;
  typedef typename Tab_traits::Traits Traits;
  typedef typename Tab_traits::Curve Curve;
  typedef typename Tab_traits::Xcurve Xcurve;
  typedef typename Tab_traits::Base_curve Base_curve;
  typedef typename Tab_traits::Data Data;
  typedef typename Tab_traits::Pm_curve_iter Pm_curve_iter;
  typedef typename Tab_traits::Pm_curve_const_iter Pm_curve_const_iter;
  typedef typename Tab_traits::Locate_type Locate_type;
  typedef typename Tab_traits::Pm_point_2 Pm_point_2;
  typedef typename Tab_traits::Halfedge_handle Halfedge_handle;
  typedef typename Tab_traits::Face_handle Face_handle;
  typedef typename Tab_traits::Ccb_halfedge_circulator 
  Ccb_halfedge_circulator;
  typedef typename Tab_traits::Holes_iterator Holes_iterator;
  typedef typename Tab_traits::Halfedge_iterator Halfedge_iterator;
  typedef typename Tab_traits::Hafledge_list Hafledge_list;
  typedef typename Tab_traits::Hafledge_list_iterator 
  Hafledge_list_iterator;
  typedef typename Tab_traits::Pm Pm;
  typedef typename Tab_traits::Vertex_iterator Vertex_iterator;
  typedef typename Tab_traits::Halfedge_around_vertex_circulator
  Halfedge_around_vertex_circulator;
  typedef typename Tab_traits::Edge_iterator Edge_iterator;
  typedef typename Tab_traits::Halfedge      Halfedge;
  typedef typename Tab_traits::Face_iterator  Face_iterator;
  typedef typename Tab_traits::Trap_point_location Trap_point_location;
  typedef typename Tab_traits::Naive_point_location Naive_point_location;
  typedef typename Tab_traits::Simple_point_location Simple_point_location;
  typedef typename Tab_traits::Walk_point_location Walk_point_location;

private:
  // function object - FillFace
  class FillFace
  {
    /*! */
    Qt_widget_demo_tab<Tab_traits> *ptr;

  public:
    /*! constructor */
    FillFace(Qt_widget_demo_tab<Tab_traits>* tab) : ptr(tab){}

    /*!
     */
    void
    operator()(typename Qt_widget_demo_tab<Tab_traits>::Face_handle& face) 
    {
      ptr->m_tab_traits.fill_face(ptr,face);
    }
  };
  
  /*!
   */
  class OverLay
  {
    Qt_widget_demo_tab<Tab_traits> *ptr;
    std::vector<QColor> overlay_colors ;

  public:
    /*! constructor */
    OverLay(Qt_widget_demo_tab<Tab_traits> * tab,
            std::vector<QColor> colors) : ptr(tab),overlay_colors(colors){}

    /*!
     */
    void
    operator()(typename Qt_widget_demo_tab<Tab_traits>::Face_handle& face) 
    {
      ptr->overlay(face,overlay_colors);
    }
  };

public:
  /*! m_tab_traits - the traits object */
  Tab_traits m_tab_traits;

  /*! m_curves_arr - pointer for the tab planar map */
  Curves_arr *m_curves_arr;

  /*! prev_curves_arr - for undo operation */
  Curves_arr m_prev_curves_arr;

  /*! Original Traits */
  Traits m_traits;

  /*! the curve to be merged */
  Halfedge_iterator closest_curve;

  /*! the second curve to be merged */
  Halfedge_iterator second_curve;

  /*! the first point in the split curve */
  Pm_point_2 split_point;

  /*! list of removable halfedge iterators (created by move event when
   * DELETE option is on
   */
  Hafledge_list removable_halfedges;

  /*! pointer to the point location strategy */
  void * m_strategy;

  
  /*! constructor 
   *\ param t - widget traits type
   *\ param parent - widget parent window
   *\ param tab_number - widget program index
   */
  Qt_widget_demo_tab(TraitsType t, Strategy _strategy, QWidget * parent = 0,
                     int tab_number = 1):
    Qt_widget_base_tab(t ,_strategy, parent, tab_number)
  {
    switch(strategy)
    {
     case NAIVE:
      {
       m_strategy = new Naive_point_location();
       m_curves_arr = new Curves_arr((Naive_point_location*)m_strategy);
       break;
      }

     case TRAP:
      {
       m_strategy = new Trap_point_location();
       m_curves_arr = new Curves_arr((Trap_point_location*)m_strategy);
       break;
      }

     case SIMPLE:
      {
       m_strategy = new Simple_point_location();
       m_curves_arr = new Curves_arr((Simple_point_location*)m_strategy);
       break;
      }

     case WALK:
      {
       m_strategy = new Walk_point_location();
       m_curves_arr = new Curves_arr((Walk_point_location*)m_strategy);
       break;
      }
    }

    // set the unbounded face initial color
    m_curves_arr->unbounded_face()->set_info(def_bg_color);   
  }
  
  /*! destructor - delete the planar map and the point location pointer
   */
  virtual ~Qt_widget_demo_tab() 
  {
    delete m_curves_arr;
    // delete the point location strategy object
     switch(strategy)
    {
     case NAIVE:
      delete (Naive_point_location*)m_strategy;
      break;

     case TRAP:
      delete (Trap_point_location*)m_strategy;
      break;

     case SIMPLE:
      delete (Simple_point_location*)m_strategy;
      break;

     case WALK:
      delete (Walk_point_location*)m_strategy;
      break;
    }
  }
  
  ///*! save previous pm */
  //void save_prev_pm()
  //{
  //  m_prev_curves_arr = m_curves_arr;
  //}


  /*! draw - called everytime something changed, draw the PM and mark the 
   *         point location if the mode is on.
   */
  void draw()
  {
    QCursor old = cursor();
    setCursor(Qt::WaitCursor);

    if ( mode == FILLFACE ) 
    {
      Locate_type lt;
      Face_handle f;
      Pm_point_2 temp_p (pl_point.x(), pl_point.y());
      Halfedge_handle e = m_curves_arr->locate(temp_p, lt);
      if(lt == Curves_arr::UNBOUNDED_FACE )
        f = m_curves_arr->unbounded_face();
      else
        f = e->face();
      
      set_face_color(f,fill_face_color);
    }

    // draw all faces (fill them with their color)
    visit_faces(FillFace(this));  

    if (snap_mode == GRID || grid)
      draw_grid();

    for (Edge_iterator ei = m_curves_arr->edges_begin(); 
         ei != m_curves_arr->edges_end(); ++ei) 
    {
      if (change_pm_color)
        setColor(pm_color);
      else
      {
        int i = (ei->curve()).get_data().m_index;
        setColor(colors[i]);
      }
      m_tab_traits.draw_xcurve(this , ei->curve() );
    }
    
    // Go over all vertices and for each vertex check the 
    // index numbers of the base curves that go through 
    // it and paint the point if they are different (beacuse ew want to
    // color red the intersection opints between two different planar maps
    // which are overlayed
    *this << CGAL::DISC;
    static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(m_vertex_width);

    Vertex_iterator   vit;
    for (vit = m_curves_arr->vertices_begin(); 
         vit != m_curves_arr->vertices_end(); vit++)
    {
      Halfedge_around_vertex_circulator 
        eit,eit2, first = (*vit).incident_halfedges();
      
      eit = first;
      setColor(Qt::red);
      int ind1, ind2;
      
      eit2 = first;
      do
      { // find (if exist) a different index than the tab index
        ind2 = (*eit2).curve().get_data().m_index;
        if (ind2 != index)
          break;
        eit2++;
      } while (eit2 != first);

      do 
      {
        ind1 = (*eit).curve().get_data().m_index;
        
        // Keep track of IDs we haven't seen before.
        if (ind1 != ind2 && ind1 != index && ind2 != index)
        {
          //const Pm_point_2& p = (*vit).point();
          Coord_point p(CGAL::to_double((*vit).point().x()) /
                        m_tab_traits.COORD_SCALE, 
                        CGAL::to_double((*vit).point().y()) /
                        m_tab_traits.COORD_SCALE); 
          static_cast<CGAL::Qt_widget&>(*this) << p;
          break;
        }
        
        eit++;
        
        // draw all vertexes of the planar map is 'draw_vertex' is true
        // draw_vertex is a flag that indicates if we draw the vertexes
        if (eit == first && draw_vertex)
        {
          if (change_pm_color)
            setColor(pm_color);
          else
            setColor(colors[ind2]);
          //const Pm_point_2& p = (*vit).point();
          Coord_point p(CGAL::to_double((*vit).point().x()) /
                        m_tab_traits.COORD_SCALE, 
                        CGAL::to_double((*vit).point().y()) /
                        m_tab_traits.COORD_SCALE); 
          static_cast<CGAL::Qt_widget&>(*this) << p;
        }
      } while (eit != first);
    }
    
    if (mode == POINT_LOCATION && 
        ! (m_curves_arr->halfedges_begin() == m_curves_arr->halfedges_end()))
    {
      static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(3);
      setColor(Qt::yellow);
      
      Locate_type lt;
      Pm_point_2 temp_p (pl_point.x(), pl_point.y());
      Halfedge_handle e = m_curves_arr->locate(temp_p, lt);
      
      //color the outer face 
      Face_handle f = e->face();
      if (f->does_outer_ccb_exist()) // its an inside face
      {
        Ccb_halfedge_circulator cc=f->outer_ccb();
        do {
          m_tab_traits.draw_xcurve(this , cc->curve() );
        } while (++cc != f->outer_ccb());
      }

      
      //color the holes
      Holes_iterator hit, eit = f->holes_end();
      for (hit = f->holes_begin(); hit != eit; ++hit) 
      {
        Ccb_halfedge_circulator cc = *hit; 
        do 
        {
          m_tab_traits.draw_xcurve(this , cc->curve() );
          cc++;
        } while (cc != *hit);
      }
      static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(m_line_width);
    }
    
    if (mode == RAY_SHOOTING && 
        !(m_curves_arr->halfedges_begin() == m_curves_arr->halfedges_end()))
    {
      Coord_point up;
      Locate_type lt;
      Pm_point_2 temp_p (pl_point.x(), pl_point.y());
      Halfedge_handle e = 
        m_curves_arr->vertical_ray_shoot(temp_p, lt ,ray_shooting_direction);
      
      setColor(Qt::black);
      static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(1);

      Coord_point pl_draw(pl_point.x() / m_tab_traits.COORD_SCALE , 
                          pl_point.y() / m_tab_traits.COORD_SCALE);

      if (ray_shooting_direction)
      {
        if (lt == Curves_arr::UNBOUNDED_FACE)
        {
          up = Coord_point(pl_draw.x() , y_max());
          static_cast<CGAL::Qt_widget&>(*this) << Coord_segment(pl_draw, up);
        }
        else // we shoot something
        {
          Pm_point_2 p1c1(pl_point.x() , y_max() * m_tab_traits.COORD_SCALE);
          Pm_point_2 p2c1(pl_point.x() , pl_point.y());
          const Xcurve c1 = m_tab_traits.curve_make_x_monotone(p1c1 , p2c1);
          const Xcurve c2 = e->curve();
          Pm_point_2 most_left(x_min() * m_tab_traits.COORD_SCALE,
                               pl_point.y());
          CGAL::Object res =
            m_traits.nearest_intersection_to_right(c1, c2, most_left);
          Pm_point_2 p1;
          if (CGAL::assign(p1, res)) {
            Coord_type y1 =
              CGAL::to_double(p1.y()) / m_tab_traits.COORD_SCALE;
            up = Coord_point(pl_draw.x(), y1);
            static_cast<CGAL::Qt_widget&>(*this) << Coord_segment(pl_draw,
                                                                  up);
          }
          //! \todo what if the intersection is empty, or a subcurve?
        }
  
        // draw an arrow that points to 'up' point
        int x = this->x_pixel(CGAL::to_double(up.x()));
        int y = this->y_pixel(CGAL::to_double(up.y()));

        this->get_painter().drawLine(x-7 , y+7 , x , y);
        this->get_painter().drawLine(x+7 , y+7 , x , y);
      }
      else // down ray shooting
      {
        Coord_point down;
        if (lt == Curves_arr::UNBOUNDED_FACE)
        {
          down = Coord_point(pl_draw.x() , y_min());
          static_cast<CGAL::Qt_widget&>(*this) << Coord_segment(pl_draw ,
                                                                down);
        }
        else // we shoot something
        {
          Pm_point_2 p1c1(pl_point.x() , y_min() * m_tab_traits.COORD_SCALE);
          Pm_point_2 p2c1(pl_point.x() , pl_point.y());
          const Xcurve c1 = m_tab_traits.curve_make_x_monotone(p1c1 , p2c1);
          const Xcurve c2 = e->curve();
          Pm_point_2 most_right(x_max() * m_tab_traits.COORD_SCALE,
                                pl_point.y());

          CGAL::Object res =
            m_traits.nearest_intersection_to_left(c1, c2, most_right);
          Pm_point_2 p1;
          if (CGAL::assign(p1, res)) {
            Coord_type y1 =
              CGAL::to_double(p1.y()) / m_tab_traits.COORD_SCALE;
            down = Coord_point(pl_draw.x(),y1);
            static_cast<CGAL::Qt_widget&>(*this) << Coord_segment(pl_draw,
                                                                  down);
          }
          //! \todo what if the intersection is empty, or a subcurve?
        }
      
        // draw an arrow that points to 'down' point
        int x = this->x_pixel(CGAL::to_double(down.x()));
        int y = this->y_pixel(CGAL::to_double(down.y()));

        this->get_painter().drawLine(x-7 , y-7 , x , y);
        this->get_painter().drawLine(x+7 , y-7 , x , y);
      }
      
      static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(3);
      setColor(Qt::red);
      
      switch (lt) {
       case (Curves_arr::VERTEX):
        {
         Coord_point p(CGAL::to_double(e->target()->point().x()) /
                       m_tab_traits.COORD_SCALE, 
                       CGAL::to_double(e->target()->point().y()) /
                       m_tab_traits.COORD_SCALE); 
         static_cast<CGAL::Qt_widget&>(*this) << p;
         break;
        }
       case (Curves_arr::UNBOUNDED_VERTEX) :
        {
          Coord_point p(CGAL::to_double(e->target()->point().x()) /
                        m_tab_traits.COORD_SCALE, 
                        CGAL::to_double(e->target()->point().y()) /
                        m_tab_traits.COORD_SCALE); 
          static_cast<CGAL::Qt_widget&>(*this) << p;
        break;
        }
       case (Curves_arr::EDGE):
        m_tab_traits.draw_xcurve(this , e->curve() );
        break;

       case (Curves_arr::UNBOUNDED_EDGE) :
        m_tab_traits.draw_xcurve(this , e->curve() );
        break;

       case (Curves_arr::FACE) :
        break;

       case (Curves_arr::UNBOUNDED_FACE) :
        break;
      }                 
      static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(m_line_width);
    }
    setCursor(old);
  }

  /*!
   */
  void update_colors(std::vector<QColor> colors)
  {
    OverLay overlay_ob(this, colors);
    visit_faces(overlay_ob);
  }
  
  /*!
   */
  void set_face_color(Face_handle &f ,QColor& c)
  {  
    f->set_info(c);
    if( ! f->does_outer_ccb_exist() || empty)
      set_unbounded_face_color(c); 
  }

  /*!
   */
  template <class Function>
  void visit_faces(Function func)
  {
    Face_iterator  fi=m_curves_arr->faces_begin();
    for( ; fi != m_curves_arr->faces_end() ; ++fi )
      fi->set_visited(false);
    Face_handle ub = m_curves_arr->unbounded_face();
    visit_face_rec (ub,func) ;
}


  /*! antenna - return true if the halfedge and its
   *  twin point to the same face.
   */
  bool antenna(Halfedge & h)
  {
    Halfedge twin = *(h.opposite());
    return (twin.face() == h.face());
  }

  /*! draw a face and all its holes recursively
   */
  template<class Function>
  void visit_face_rec( Face_handle &f, Function func )
  {
    if (! f->visited())
    {
      Holes_iterator hit; // holes iterator
      func(f);
      f->set_visited(true);
      for(hit= f->holes_begin() ; hit!=f->holes_end() ; ++hit)
      {
        Ccb_halfedge_circulator cc = *hit;
        do {
          Halfedge he = *cc; 
          Halfedge he2 = *(he.opposite());
          Face_handle inner_face = he2.face(); // not sure about that
          if (antenna(he))
            continue;
          
          // move on to next hole
          visit_ccb_faces(inner_face , func); 
        }while (++cc != *hit);
      }// for
    }
  }// visit_face_rec

  template <class Function>
  void visit_ccb_faces(Face_handle & fh, Function func)
  {
    visit_face_rec(fh,func);
    Ccb_halfedge_circulator cc=fh->outer_ccb();
    do {
      Halfedge he = *cc;
      if(! he.opposite()->face()->visited())
      {
        Face_handle nei = (Face_handle) he.opposite()->face();
        visit_ccb_faces( nei ,func );
      }
      //created from the outer boundary of the face
    } while (++cc != fh->outer_ccb());
  }

  /*!
   */
  void overlay (Face_handle f , std::vector<QColor> & colors)
  {
    f->assign_overlay_info(colors); 
    if (f->does_outer_ccb_exist())  // f is not the unbounded face
    {
      /* running  around the outer of the face  */
      Ccb_halfedge_circulator cc = f->outer_ccb();
      do {
        Halfedge he = *cc;  // get the halfedge
        Data d = he.curve().get_data();  // get the data of the halfedge
        // get the original halfedge (from the original PM)
        Halfedge_handle original_he = d.halfedge_handle, temp_he;

        // getting the index of the original PM of the curve 
        int index = d.m_index;   
        if(m_tab_traits.curve_has_same_direction(cc))
          temp_he = original_he;
        else
          temp_he=(Halfedge_handle)original_he->opposite();

        // the original color of the face        
        QColor original_face_color = temp_he->face()->info(); 
        // update the colors vector in the face
        f->set_overlay_info( index , original_face_color);  
        // we want to update the colors vector to pass
        colors[index] = original_face_color; 
        // the information down the recurtion process.
        
      } while (++cc != f->outer_ccb());
      // blend the colors
      QColor c = blend_colors(f->OverlayInfoBegin() , f-> OverlayInfoEnd());
      f->set_info(c);
    }  
    else // f is the unbounded face
    {  
      // blend the colors
      QColor c = blend_colors(colors.begin() , colors.end() );
      f->set_info(c);
      set_unbounded_face_color(c);
    }
  }

  /*! draw_grid - draw the grid
   */
  void draw_grid()
  {
    setColor(Qt::white);
    static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(1);
    // get the edge coordinate
    int min_x = static_cast<int> (x_min());
    int max_x = static_cast<int> (x_max());
    int min_y = static_cast<int> (y_min());
    int max_y = static_cast<int> (y_max());
    
    // calculate cube size (minimum of 1)
    //int cube_size_x = std::max(1, abs(max_x - min_x)/20);
    //int cube_size_y = std::max(1, abs(max_y - min_y)/20);
    if (cube_size < std::abs(max_x - min_x)/40 ||
        cube_size < std::abs(max_y - min_y)/40)
      cube_size = std::max(std::max(1, std::abs(max_x - min_x)/20),
                           std::max(1, std::abs(max_y - min_y)/20));
    
    int cube_size_x = cube_size;
    int cube_size_y = cube_size;
    // draw the grid lines
    for (int i = min_x; i <= max_x; i += cube_size_x)
      static_cast<CGAL::Qt_widget&>(*this) <<
        Coord_segment(Coord_point(i, max_y + cube_size_y),
                      Coord_point( i , min_y - cube_size_y));
    for (int i = min_y; i <= max_y; i += cube_size_y)
      static_cast<CGAL::Qt_widget&>(*this) <<
        Coord_segment(Coord_point( max_x + cube_size_x , i ),
                      Coord_point( min_x - cube_size_x , i ));
  }
  
  /*! mousePressEvent - mouse click on the tab 
   *\ param e - mouse click event
   */
  void mousePressEvent(QMouseEvent *e)
  {
    QCursor old = cursor();
    setCursor(Qt::WaitCursor);

    if (mode == POINT_LOCATION || mode == RAY_SHOOTING || mode == FILLFACE)
    {
      mousePressEvent_point_location( e );
      setCursor(old);
      return;
    }

    if (mode == DELETE)
    {
      Hafledge_list_iterator itr;
      for (itr = removable_halfedges.begin();
           itr != removable_halfedges.end() ; ++itr)
        m_curves_arr->remove_edge(*itr);

      removable_halfedges.clear(); // clear the list which is now irrelevant
      redraw();

      if( m_curves_arr->number_of_vertices() == 0 )
        empty = true;
      setCursor(old);
      return;
    }

    if (mode == INSERT)
    {
      Coord_type x, y;
      x_real(e->x(), x);
      y_real(e->y(), y);
      Coord_point p = get_point(x,y);
      
      lock();
      QColor old_color = color();
      RasterOp old_rasterop=rasterOp();
      get_painter().setRasterOp(XorROP);
      
      insert( e , p);
      
      setRasterOp(old_rasterop);
      setColor(old_color);
      unlock();
      if( m_curves_arr->number_of_vertices() > 0 )
        empty = false;
      setCursor(old);
      return;
    }
    if (mode == DRAG)
    {
      mousePressEvent_drag(e);
      setCursor(old);
      return;
    }
    if (mode == MERGE)
    {
      mousePressEvent_merge(e);
      setCursor(old);
      return;
    }
    if (mode == SPLIT)
    {
      Coord_type x, y;
      x_real(e->x(), x);
      y_real(e->y(), y);
      Coord_point p = get_point(x,y);
      
      lock();
      QColor old_color = color();
      RasterOp old_rasterop=rasterOp();
      get_painter().setRasterOp(XorROP);
      
      split( e , p);
      
      setRasterOp(old_rasterop);
      setColor(old_color);
      unlock();
      first_time = true;
      redraw();
      setCursor(old);
      return;
    }
  }
  
  /*! insert - insert a curve to the planar map 
   *\ param e - mouse click event
   *\ param p - the pressed point
   */
  void insert( QMouseEvent *e , Coord_point p)
  {
    if(e->button() == Qt::LeftButton && is_pure(e->state()))
    {
      if(!active)
      {
        active = true;
        m_tab_traits.first_point( p , mode );
      } 
      else
      {
        //show the last rubber as edge of the polygon
        m_tab_traits.middle_point( p , this );
      }
    }
    // finish polyline draw with right button click 
    else if (active && e->button() == Qt::RightButton && is_pure(e->state())) 
    {
      m_tab_traits.last_point( p , this );
    }    
  }
  
  /*! split - split a xcurve in to 2 xcurves  
   *\ param e - mouse click event
   *\ param p - the pressed point
   */
  void split( QMouseEvent *e , Coord_point p)
  {
    if(e->button() == Qt::LeftButton && is_pure(e->state()))
    {
      if(!active)
      {
        active = true;
        m_tab_traits.first_point( p , mode);
        split_point = Pm_point_2( p.x() * m_tab_traits.COORD_SCALE ,
                                  p.y() * m_tab_traits.COORD_SCALE);
      } 
      else
      {
        active = false;
        Pm_point_2 split_point2 =
          Pm_point_2(p.x() * m_tab_traits.COORD_SCALE,
                     p.y() * m_tab_traits.COORD_SCALE);
        const Xcurve split_curve = 
          m_tab_traits.curve_make_x_monotone(split_point , split_point2);
        Pm_point_2 p1;
        Pm_point_2 p_right;
        if (split_point.x() < split_point2.x())
          p_right = split_point;
        else
          p_right = split_point2;
        Halfedge_iterator hei;
        for (hei = m_curves_arr->halfedges_begin();
             hei != m_curves_arr->halfedges_end(); ++hei) 
        {
          const Xcurve & xcurve = hei->curve();
          m_tab_traits.draw_xcurve(this, xcurve);
          CGAL::Object res =
            m_traits.nearest_intersection_to_right(split_curve,
                                                   xcurve,p_right);
          if (CGAL::assign(p1, res))
            break;
        }

        Vertex_iterator   vit;
        bool is_already_vertex = false;
        // we dont want to split an already existed vertex...
        for (vit = m_curves_arr->vertices_begin(); 
             vit != m_curves_arr->vertices_end(); vit++)
        {
          Pm_point_2 temp = (*vit).point();
          if (p1 == temp)
            is_already_vertex = true;
        }
        m_tab_traits.draw_xcurve(this, hei->curve());
        if (hei != m_curves_arr->halfedges_end() && !is_already_vertex)
          m_tab_traits.split_edge(hei , p1 , this);
        
      }// else
    }    
  }

  /*! mousePressEvent_point_location - creats the point location point 
   *\ param e - mouse click event
   */
  void mousePressEvent_point_location(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton
       && is_pure(e->state()))
    {
      Coord_type x, y;
      x_real(e->x(), x);
      y_real(e->y(), y);

      new_object(make_object(Coord_point(x * m_tab_traits.COORD_SCALE, 
                                         y * m_tab_traits.COORD_SCALE)));
    }
  }
  
  /*! is_pure - insure no special button is pressed 
   *\ param s - keyboard modifier flags that existed 
   *  immediately before the event occurred.
   *\ return true if one of them existed, false otherway.
   */
  bool is_pure(Qt::ButtonState s)
  {
    if((s & Qt::ControlButton) ||
       (s & Qt::ShiftButton) ||
       (s & Qt::AltButton))
      return 0;
    else
      return 1;
  }
  
  /*! dist  
   *\ param x1,y1,x2,y2 - points coordinates
   *\ return the distance between 2 points 
   */
  Coord_type dist(Coord_type x1, Coord_type y1, Coord_type x2, Coord_type y2)
  {
    return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
  }
  
  /*! getMid 
   *\ param coord - coord vulue apon the grid
   *\ return the closest grid point 
   */
  Coord_type getMid(Coord_type coord, int my_min, int my_max)
  {
    //int cube_size = std::max(1, abs(my_max - my_min)/20);
    Coord_type d = static_cast<Coord_type>(cube_size)/2;
    for (int i = my_min - cube_size; i <= my_max; i += cube_size)
    {
      Coord_type id = static_cast<Coord_type>(i); 
      if (coord >= id - d && coord <= id + d)
      {
        Coord_type ans  = static_cast<Coord_type>(i);
        return ans;
      }
    }
    return 0;
  }
  
  /*! find_removeable_halfedges - find removable curve in the tab 
   *\ param e - mouse click event
   */
  void find_removable_halfedges(QMouseEvent *e)
  {
    //  if the PM is empty do nothing
    if( m_curves_arr->number_of_vertices() == 0)
      return;
   
    if(!removable_halfedges.empty())
    {
      int i = (removable_halfedges.front()->curve()).get_data().m_index;
      setColor(colors[i]);
      Hafledge_list_iterator itr;
      for (itr = removable_halfedges.begin();
          itr != removable_halfedges.end() ; ++itr)
        m_tab_traits.draw_xcurve(this,(*itr)->curve());

      // clear the previous list which is now irrelevant
      removable_halfedges.clear(); 
    }

    // get the point of the mouse
    Coord_point p(x_real(e->x()) * m_tab_traits.COORD_SCALE ,
                  y_real(e->y()) * m_tab_traits.COORD_SCALE);
    
    bool is_first = true;       
    Coord_type min_dist = 0;
    Halfedge_iterator hei;
    Halfedge_iterator closest_hei;
    
    for (hei = m_curves_arr->halfedges_begin();
         hei != m_curves_arr->halfedges_end(); ++hei) 
    {
      Xcurve & xcurve = hei->curve();
      Coord_type dist = m_tab_traits.xcurve_point_distance(p, xcurve , this);
      if (is_first || dist < min_dist)
      {
        min_dist = dist;
        closest_hei = hei;
        is_first = false;
      }    
    }
    // now 'closest_hei' holds the cloeset halfedge to the point of the mouse

    if (remove_org_curve && !read_from_file)
    {
      const Base_curve * org_curve =
        m_tab_traits.get_origin_curve(closest_hei->curve());
      Hafledge_list li;
      Hafledge_list_iterator result;
      for (hei = m_curves_arr->halfedges_begin();
           hei != m_curves_arr->halfedges_end(); ++hei) 
      {
        const Base_curve * curve =
          m_tab_traits.get_origin_curve(hei->curve());
        result = std::find(li.begin(), li.end(), hei);
        if (curve == org_curve && result == li.end())
        {
          li.push_back(hei->twin());
          //m_curves_arr->remove_edge(hei);
          setColor(Qt::red);  // highlight the removable edge with red color
          m_tab_traits.draw_xcurve(this,hei->curve());
          removable_halfedges.push_back(hei);
        }
      }
    }
    else
    {
      // m_curves_arr->remove_edge(closest_hei);
      setColor(Qt::red);  // highlight the removable edge with red color
      m_tab_traits.draw_xcurve(this,closest_hei->curve());
      removable_halfedges.push_back(closest_hei);
    }
  }

  /*! mouseMoveEvent - enable seeing the line to be drawen 
   *\ param e - mouse click event
   */
  void mouseMoveEvent(QMouseEvent *e)
  {
    static_cast<CGAL::Qt_widget&>(*this) << CGAL::LineWidth(m_line_width);
    if (mode == DELETE)
      // find removable edges , store them in the list 
      find_removable_halfedges(e);
    //'removable_halfedges' and highlight them

    if (mode == DRAG)
    {
      mouseMoveEvent_drag(e);
      return;
    }
    if (mode == MERGE && !first_time_merge)
    {
      if (second_curve != m_curves_arr->halfedges_end())
      {
        int i = (second_curve->curve()).get_data().m_index;
        setColor(colors[i]);
        m_tab_traits.draw_xcurve(this,second_curve->curve());
      }
      Coord_type x, y;
      x_real(e->x(), x);
      y_real(e->y(), y);
      Coord_point p(x * m_tab_traits.COORD_SCALE,
                    y * m_tab_traits.COORD_SCALE);
      second_curve = m_curves_arr->halfedges_end();
      m_tab_traits.find_close_curve(closest_curve, second_curve, p, this,
                                    true);
      setColor(Qt::red);
      m_tab_traits.draw_xcurve(this,closest_curve->curve());
      if (second_curve != m_curves_arr->halfedges_end())
      {
        setColor(Qt::green);
        m_tab_traits.draw_xcurve(this,second_curve->curve());
      }
      else
      {
        first_time_merge = true;
        redraw();
      }
      return;
    }// merge

    if(active)
    {
      Coord_type x, y;
      x_real(e->x(), x);
      y_real(e->y(), y);
      Coord_point p = get_point(x,y);
      RasterOp old_raster = rasterOp();//save the initial raster mode
      setRasterOp(XorROP);
      lock();

      setColor(Qt::green);
      
      if(!first_time)
        m_tab_traits.draw_last_segment(this);
      
      m_tab_traits.draw_current_segment( p , this);
      
      unlock();
      setRasterOp(old_raster);
      first_time = false;
    }
  }
  
  /*! leaveEvent - hide the line if you leave the widget's area on the screen 
   *\ param e - mouse click event
   */
  void leaveEvent(QEvent *e)
  {
    if(active)
    {
      RasterOp old_raster = rasterOp();//save the initial raster mode
      QColor old_color = color();
      lock();
      setRasterOp(XorROP);
      setColor(Qt::green);
      m_tab_traits.draw_last_segment(this);
      setRasterOp(old_raster);
      setColor(old_color);
      unlock();
      first_time = true;
    }
  }
  
  /*! get_point 
   *\ params x,y - the mouse clicked point coordinates
   *\    return a point according to the current snap mode and
   *  recent points. 
   */
  Coord_point get_point(Coord_type x, Coord_type y)
  {
    int xmin = static_cast<int> (x_min());
    int xmax = static_cast<int> (x_max());
    int ymin = static_cast<int> (y_min());
    int ymax = static_cast<int> (y_max());
    Coord_type d = std::max(0.5 , (x_max() - x_min())/40);
    switch ( snap_mode ) {
     case POINT:
      {
       Coord_type min_dist = 0;
       Coord_point closest;
       
       if( m_curves_arr->number_of_vertices() == 0 ) 
         return Coord_point(x , y);
       
       min_dist = m_tab_traits.closest_point(x,y,closest,this);                
       
       if (min_dist <= d)
         return closest;
       else
         return Coord_point(x , y);
       
       break;
      }
     case GRID:
      return Coord_point(getMid(x, xmin, xmax), 
                         getMid(y, ymin, ymax) );

     case NONE: break;
    }
    return Coord_point(x,y);
  }
  
  /*! mousePressEvent_drag - change the Cursor on the drag mode
   *  mouse pressed event
   *\ param e - mouse click event
   */
  void mousePressEvent_drag(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton 
       && is_pure(e->state()))
    {
      setCursor(QCursor( QPixmap( (const char**)holddown_xpm)));
      if (!on_first){
        first_x = e->x();
        first_y = e->y();
        on_first = TRUE;
      }    
    }
  }
  
  /*! mouseReleaseEvent - change the Cursor on the drag mode
   *  mouse pressed event and move the widget center according
   *  to the drag distance.
   *\ param e - mouse release event
   */
  void mouseReleaseEvent(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton
       && mode == DRAG
       && is_pure(e->state()))
    {
      setCursor(QCursor( QPixmap( (const char**)hand_xpm)));
      double x, y, xfirst2, yfirst2;
      x_real(e->x(), x);
      y_real(e->y(), y);
      x_real(first_x, xfirst2);
      y_real(first_y, yfirst2);
      
      double    xmin, xmax, ymin, ymax, distx, disty;
      if(x < xfirst2) {xmin = x; xmax = xfirst2;}
      else {xmin = xfirst2; xmax = x;};
      if(y < yfirst2) {ymin = y; ymax = yfirst2;}
      else {ymin = yfirst2; ymax = y;};
      distx = xfirst2 - x;
      disty = yfirst2 - y;
      move_center(distx, disty);
      on_first = FALSE;
    }
  }
  
  /*! mouseMoveEvent_drag - calculate new widget position
   *\ param e - mouse release event
   */
  void mouseMoveEvent_drag(QMouseEvent *e)
  {
    if(on_first)
    {        
      int x = e->x();
      int y = e->y();
      //save the last coordinates to redraw the screen
      x2 = x;
      y2 = y;
      wasrepainted = FALSE;
    }
  };
  
  /*! mousePressEvent_merge -  merge mode
   *  mouse pressed event
   *\ param e - mouse click event
   */
  void mousePressEvent_merge(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton && is_pure(e->state()))
    {
      if( m_curves_arr->number_of_vertices() == 0 )
      return;

      setColor(Qt::red);
      Coord_point p(x_real(e->x()) * m_tab_traits.COORD_SCALE ,
                    y_real(e->y()) * m_tab_traits.COORD_SCALE);
      bool is_first = true;
      Coord_type min_dist = 0;

      if (first_time_merge)
      {
        first_time_merge = false;
        Halfedge_iterator hei;
        //closest_curve = m_curves_arr->halfedges_end();
    
        for (hei = m_curves_arr->halfedges_begin();
             hei != m_curves_arr->halfedges_end(); ++hei) 
        {
          Vertex_iterator   vis = hei->source();
          Vertex_iterator   vit = hei->target();
          if (vis->degree() != 2 && vit->degree() != 2)
            continue;
          Xcurve & xcurve = hei->curve();
          Coord_type dist = m_tab_traits.xcurve_point_distance(p, xcurve,
                                                               this);
          if (is_first || dist < min_dist)
          {
            min_dist = dist;
            closest_curve = hei;
            is_first = false;
          }    
        }
        if (is_first) // we didn't find any "good" curve
        {
          first_time_merge = true;
          return;
        }
        m_tab_traits.draw_xcurve(this , closest_curve->curve() );
        second_curve = m_curves_arr->halfedges_end();
      }
      else
      {
        first_time_merge = true;
        m_tab_traits.find_close_curve(closest_curve, second_curve, p, this,
                                      false);
        redraw();
      }
    }
  }

  /*!
   */
  void update_curves_date_after_split(Halfedge_handle & e1, Xcurve & c1,
                                      Xcurve & c2)
  {
    Xcurve my_c1 , my_c2;  //temp variable

    // check that e1 is indeed the halfede of c1
    if(m_tab_traits.is_curve_and_halfedge_same_direction(e1,c1)) 
    {
      my_c1 = c1;
      my_c2 = c2;
    }
    else
    {
      my_c1 = c2;
      my_c2 = c1;
    }

    // update my_c1
    Data d1 = my_c1.get_data();

    if(m_tab_traits.is_curve_and_halfedge_same_direction(e1 , my_c1))
      d1.halfedge_handle = e1;
    else
      d1.halfedge_handle = (Halfedge_handle)e1->opposite();

    e1->curve().set_data( d1 );
    e1->opposite()->curve().set_data( d1 );

    // update my_c2
    Data d2 = my_c2.get_data();
    if (m_tab_traits.is_curve_and_halfedge_same_direction
        ((Halfedge_handle)e1->next() , my_c2))
      d2.halfedge_handle = (Halfedge_handle)e1->next();
    else
      d2.halfedge_handle = (Halfedge_handle) e1->next()->opposite();

    e1->next()->curve().set_data( d2 );
    e1->next()->opposite()->curve().set_data( d2 );
  }

  /*!
   */
  void update_curve_data_after_merge(Halfedge_handle &h ,Xcurve &c)
  { 
    Data d = c.get_data();
    if(m_tab_traits.is_curve_and_halfedge_same_direction(h , c))
      d.halfedge_handle = h;
    else
      d.halfedge_handle = (Halfedge_handle)h->opposite();

    h->curve().set_data( d );
    h->opposite()->curve().set_data( d );
  }
};

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

/*! class Segment_tab_traits defines the segment traits
 */
class Segment_tab_traits 
{
public:
  typedef Pm_seg_list Curves_list;
  typedef Seg_arr Curves_arr;
  typedef Seg_traits Traits;
  typedef Pm_seg_iter Pm_curve_iter;
  typedef Pm_seg_const_iter Pm_curve_const_iter;
  typedef Seg_locate_type Locate_type;
  typedef Pm_seg_point_2 Pm_point_2;
  typedef Seg_halfedge_handle Halfedge_handle;
  typedef Pm_seg_2 Curve;
  typedef Pm_xseg_2 Xcurve;
  typedef Pm_base_seg_2 Base_curve;
  typedef Seg_face_handle Face_handle;
  typedef Seg_ccb_halfedge_circulator Ccb_halfedge_circulator;
  typedef Seg_holes_iterator Holes_iterator;
  typedef Seg_pm::Halfedge_iterator Halfedge_iterator;
  typedef std::list<Halfedge_iterator> Hafledge_list;
  typedef Hafledge_list::iterator Hafledge_list_iterator;
  typedef Curves_arr::Vertex_iterator Vertex_iterator;
  typedef Seg_pm Pm;
  typedef Curves_arr::Vertex_iterator Vertex_iterator;
  typedef Curves_arr::Halfedge_around_vertex_circulator
  Halfedge_around_vertex_circulator;
  typedef Curves_arr::Edge_iterator Edge_iterator;
  typedef Curve_data Data;
  typedef Seg_halfedge           Halfedge;
  typedef  Seg_face_iterator    Face_iterator;
  
  //point location
  typedef Seg_trap_point_location      Trap_point_location;
  typedef Seg_naive_point_location     Naive_point_location;
  typedef Seg_simple_point_location    Simple_point_location;
  typedef Seg_walk_point_location      Walk_point_location;
  //typedef Seg_lenmarks_point_location  Lenmarks_point_location;
 
 
public:
 
  /*! coordinate scale - used in conics*/
  int COORD_SCALE;

  /*! constructor */
  Segment_tab_traits():
  COORD_SCALE(1)
  {}
  
  /*! distructor */
  ~Segment_tab_traits()
  {}

  /*! curve_has_same_direction - return true if the halfegde and
   *  its curve has the same direction
   */
  bool curve_has_same_direction( Ccb_halfedge_circulator &cc)
  {
    return (cc->curve().source() == cc->source()->point());
  }

  /*! check if curve and its halfedge are at the same direction */
  bool is_curve_and_halfedge_same_direction (const Halfedge_handle & he,
                                             const Xcurve & cv)
  {
    return (he->source()->point() == cv.source());
  }

  /*! fill_face - fill a face with its color (which is stored at the face)
   * it creates a polyong from the outer boundary of the face and 
   * uses CGAL opertaor << of polygons 
   */
  void fill_face(Qt_widget_demo_tab<Segment_tab_traits> * w , Face_handle f)
  {
    if (f->does_outer_ccb_exist())  // f is not the unbounded face
    {
      std::list< Coord_point > pts; // holds the points of the polygon         

      /* running with around the outer of the face and generate from it
       * polygon
       */
      Ccb_halfedge_circulator cc=f->outer_ccb();
      do {
        Coord_type x = CGAL::to_double(cc->source()->point().x());
        Coord_type y = CGAL::to_double(cc->source()->point().y());
        Coord_point coord_source(x , y);
        pts.push_back(coord_source );
        //created from the outer boundary of the face
      } while (++cc != f->outer_ccb());

      // make polygon from the outer ccb of the face 'f'
      Polygon pgn (pts.begin() , pts.end()); 

      w->setFilled(true);

      // fill the face according to its color (stored at any of her
      // incidents curves)
      if (! f->info().isValid())
        w->setFillColor(def_bg_color);
      else
        w->setFillColor(f->info());

      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);
      (*w) << pgn ;  // draw the polyong 
      w->setFilled(false);       
      w->get_painter().setPen(old_penstyle);
    }
    else
    {
      Coord_point points[4];
      points[0] = (Coord_point(w->x_min(),w->y_min()));
      points[1] = (Coord_point(w->x_min(),w->y_max()));
      points[2] = (Coord_point(w->x_max(),w->y_max()));
      points[3] = (Coord_point(w->x_max(),w->y_min()));
     
      w->setFilled(true);
      w->setFillColor(w->unbounded_face_color());
      
      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);
      (*w)<<Polygon(points , points +4 );
      w->setFilled(false);
       w->get_painter().setPen(old_penstyle);
    }
  }


  /*! draw_xcurve - use Qt_Widget operator to draw 
   *\ param w - the demo widget
   *\ c - curve to be drawen
   */
  void draw_xcurve(Qt_widget_demo_tab<Segment_tab_traits> * w , Xcurve c )
  {
    (*w) << c;
  }
  
  /*! first_point - a first point of inserted sgment
   */
  void first_point( Coord_point p , Mode m )
  {
    m_p1 = m_p2 = p;
  }
  
  /*! middle_point - the last point of a segment
   */
  void middle_point(Coord_point p , 
                    Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    if(m_p1.x() != p.x() || m_p1.y() != p.y()) 
    {
      get_segment( Coord_segment( m_p1 , p ) , w );
      w->active = false;
      //w->redraw();  // not working so I use new_object insted
      w->new_object(make_object(Coord_segment(m_p1 , p)));
    } 
  }
  
  /*! last_point - meaningless for segments
   */
  void last_point( Coord_point p , 
                   Qt_widget_demo_tab<Segment_tab_traits> * w )
  {
    return;
  }
  
  /*! get_segment - create a new segment, insert him into curves_list
   * and planar map
   */
  void get_segment( Coord_segment coord_seg ,
                    Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    Seg_notification  seg_notif;
    const Coord_point & coord_source = coord_seg.source();
    const Coord_point & coord_target = coord_seg.target();
    Pm_seg_point_2 source(coord_source.x(), coord_source.y());
    Pm_seg_point_2 target(coord_target.x(), coord_target.y());
    Pm_base_seg_2 * base_seg_p = new Pm_base_seg_2(source, target);
    Curve_data cd;
    cd.m_type = Curve_data::LEAF;
    cd.m_index = w->index;
    cd.m_ptr.m_curve = base_seg_p;
    Pm_seg_2 * seg = new Pm_seg_2( *base_seg_p, cd );
    Halfedge_handle hh = w->m_curves_arr->insert(*seg, &seg_notif);
    CGAL::Bbox_2 curve_bbox = seg->bbox();
    w->bbox = w->bbox + curve_bbox;

    //Curve_data d = hh->curve().get_data();  // get the data of the halfedge
    //   Halfedge_handle original_he = d.halfedge_handle;
  }
  
  /*! curve_point_distance - return the distance between a point 
   * and a segment
   */
  Coord_type curve_point_distance(Coord_point p, Curve * c ,
                                  Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    const Pm_seg_point_2 & source = (*c).source();
    const Pm_seg_point_2 & target = (*c).target();
    
    Coord_type x1 = CGAL::to_double(source.x());
    Coord_type y1 = CGAL::to_double(source.y());
    
    Coord_type x2 = CGAL::to_double(target.x());
    Coord_type y2 = CGAL::to_double(target.y());
    
    Coord_point coord_source(x1 , y1);
    Coord_point coord_target(x2 , y2);
    Coord_segment coord_seg(coord_source, coord_target);
    return CGAL::squared_distance( p, coord_seg);
  }
  
  /*! xcurve_point_distance - return the distance between a point
   * and a xsegment
   */
  Coord_type xcurve_point_distance(Coord_point p, Xcurve & c ,
                                   Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    const Pm_seg_point_2 & source = c.source();
    const Pm_seg_point_2 & target = c.target();
    
    Coord_type x1 = CGAL::to_double(source.x());
    Coord_type y1 = CGAL::to_double(source.y());
    
    Coord_type x2 = CGAL::to_double(target.x());
    Coord_type y2 = CGAL::to_double(target.y());
    
    Coord_point coord_source(x1 , y1);
    Coord_point coord_target(x2 , y2);
    Coord_segment coord_seg(coord_source, coord_target);
    return CGAL::squared_distance( p, coord_seg);
  }
  
  /*! get_origin_curve - return the origin base curve
   */
  const Pm_base_seg_2* get_origin_curve(const Pm_xseg_2 & xseg )
  {
    const Curve_data & curve_data = xseg.get_data();
    if (curve_data.m_type == Curve_data::LEAF) 
      return curve_data.m_ptr.m_curve;
    else // curve_data.m_type == Curve_data::INTERNAL
    {
      const Pm_xseg_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve;      
      return get_origin_curve( *xseg_p );
    }
  }
  
  /*! draw_last_segment - call from mouse move event
   */
  void draw_last_segment( Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    *w << Coord_segment( m_p1 , m_p2 );
  }
  
  /*! draw_current_segment - call from mouse move event
   */
  void draw_current_segment( Coord_point p ,
                             Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    *w << Coord_segment( m_p1 , p);
    m_p2 = p;
  }
  
  /*! closest_point - find the closest point in the planar map
   * to a clicked point
   */
  Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest,
                           Qt_widget_demo_tab<Segment_tab_traits> * w)
  {
    bool first = true;
    Coord_type x1,y1,dt,min_dist = 0;
    Vertex_iterator vit;
    for (vit = w->m_curves_arr->vertices_begin();
         vit != w->m_curves_arr->vertices_end(); vit++)
    {
      const Pm_point_2& p = (*vit).point();
      x1 = CGAL::to_double(p.x());
      y1 = CGAL::to_double(p.y());
      dt = w->dist(x1 , y1 , x , y);
      if ( dt < min_dist || first)
      {
        min_dist = dt;
        closest = Coord_point(x1 , y1);
        first = false;
      }
    }
    return min_dist;
  }

  /*! curve_make_x_monotone
   */
  const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2)
  {
    Data d;
    const Curve cv(Base_curve(p1 , p2) , d);
    std::list<Xcurve> xcurve_list;
    m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list));
    const Xcurve c1 = xcurve_list.front();
    return c1;
  }

  /*!
   */
  void find_close_curve(Halfedge_iterator &closest_curve ,Halfedge_iterator 
                        &second_curve ,Coord_point &p ,
                        Qt_widget_demo_tab<Segment_tab_traits> *w,
                        bool move_event)
  {
    bool is_first = true;
    Coord_type min_dist = 0;
    Halfedge_iterator hei;
    Pm_point_2 s = closest_curve->source()->point();
    Pm_point_2 t = closest_curve->target()->point();
    Vertex_iterator   vis = closest_curve->source();
    Vertex_iterator   vit = closest_curve->target();
    Kernel            ker;
    for (hei = w->m_curves_arr->halfedges_begin();
         hei != w->m_curves_arr->halfedges_end(); ++hei) 
    {
      Pm_point_2 s1 = hei->source()->point();
      Pm_point_2 t1 = hei->target()->point();

      if (merge_segments_precondition<Pm_point_2>(s, t, s1, t1,
                                                  vis->degree(),
                                                  vit->degree()) && 
          ker.compare_slope_2_object()(Kernel::Segment_2(s, t),
                                       Kernel::Segment_2(s1, t1)) ==
          CGAL::EQUAL)
      {
        Xcurve & xcurve = hei->curve();
        Coord_type dist = xcurve_point_distance( p, xcurve , w);
        if (is_first || dist < min_dist)
        {
          min_dist = dist;
          second_curve = hei;
          is_first = false;
        }    
      }
    }
    if (is_first) // didn't find any "good" curve
      return;

    else if (!move_event)
    {
      Pm_point_2 s1 = second_curve->source()->point();
      Pm_point_2 t1 = second_curve->target()->point();
      Base_curve * base = 0;

      if ( t == s1 )
        base = new Base_curve(s, t1);
      else if ( t == t1 )
        base = new Base_curve(s, s1);
      else if ( s == s1 )
        base = new Base_curve(t, t1);
      else if ( s == t1 )
        base = new Base_curve(t, s1);

      Curve_data cd;
      cd.m_type = Curve_data::LEAF;
      cd.m_index = w->index;
      cd.m_ptr.m_curve = base;
      Curve *seg = new Curve( *base, cd );
      std::list<Xcurve> xcurve_list;
      m_traits.curve_make_x_monotone(*seg, std::back_inserter(xcurve_list));
      Xcurve c = xcurve_list.front();
      Halfedge_handle h = w->m_curves_arr->merge_edge( closest_curve ,
                                                       second_curve , c); 
      
      w->update_curve_data_after_merge(h , c); 
      //// update c
      //
      // Curve_data d = c.get_data();
      //if(is_curve_and_halfedge_same_direction(h , c))
      //  d.halfedge_handle = h;
      //else
      //  d.halfedge_handle = (Halfedge_handle)h->opposite();
      
      //h->curve().set_data( d );
      //h->opposite()->curve().set_data( d );
      
    }
  }

  /*!
   */
  void split_edge(Halfedge_iterator &hei ,Pm_point_2 &p ,
                  Qt_widget_demo_tab<Segment_tab_traits> *w)
  {
    std::list<Xcurve> xcurve_list;

    Base_curve *base1 = new Base_curve;
    Base_curve *base2 = new Base_curve;

    Base_seg_traits  base_seg_traits;

    base_seg_traits.curve_split (hei->curve(),
                                 *base1, *base2,
                                 p);

    Curve_data cd1;
    cd1.m_type = Curve_data::LEAF;
    cd1.m_index = hei->curve().get_data().m_index;
    cd1.m_ptr.m_curve = base1;
    Curve *seg1 = new Curve( *base1, cd1 );

    m_traits.curve_make_x_monotone(*seg1, std::back_inserter(xcurve_list));
    Xcurve c1 = xcurve_list.front();

    Curve_data cd2;
    cd2.m_type = Curve_data::LEAF;
    cd2.m_index = hei->curve().get_data().m_index;
    cd2.m_ptr.m_curve = base2;
    Curve *seg2 = new Curve( *base2, cd2 );
    xcurve_list.clear();
    m_traits.curve_make_x_monotone(*seg2, std::back_inserter(xcurve_list));
    Xcurve c2 = xcurve_list.front();

    // split hei into curves : c1 ,c2 and store halfedge e1 (halfedge of c1)
    Halfedge_handle e1 = w->m_curves_arr->split_edge(hei , c1 , c2);

    // update the halfedge_handle field in the Curve_Data of c1 ,c2
    // Curve_Data

    w->update_curves_date_after_split(e1 , c1, c2);
  }

  /*! temporary points of the created segment */
  Traits m_traits;
  Coord_point m_p1,m_p2;
  
};

//////////////////////////////////////////////////////////////////////////////

/*! class Polyline_tab_traits defines the polyline traits */
class Polyline_tab_traits  
{
public:
  typedef Pm_pol_list Curves_list;
  typedef Pol_arr Curves_arr;
  typedef Pol_traits Traits;
  typedef Pm_pol_iter Pm_curve_iter;
  typedef Pm_pol_const_iter Pm_curve_const_iter;
  typedef Pol_locate_type Locate_type;
  typedef Pm_pol_point_2 Pm_point_2;
  typedef Pol_halfedge_handle Halfedge_handle;
  typedef Pm_pol_2 Curve;
  typedef Pm_xpol_2 Xcurve;
  typedef Pm_base_pol_2 Base_curve;
  typedef Pol_face_handle Face_handle;
  typedef Pol_ccb_halfedge_circulator Ccb_halfedge_circulator;
  typedef Pol_holes_iterator Holes_iterator;
  typedef Pol_pm::Halfedge_iterator Halfedge_iterator;
  typedef std::list<Halfedge_iterator> Hafledge_list;
  typedef Hafledge_list::iterator Hafledge_list_iterator;
  typedef std::vector<Pm_point_2>::iterator Point_vector_iterator;
  typedef Curve::const_iterator Curve_const_iterator;
  typedef Pol_pm Pm;
  typedef Curves_arr::Vertex_iterator Vertex_iterator;
  typedef Curves_arr::Halfedge_around_vertex_circulator
  Halfedge_around_vertex_circulator;
  typedef Curves_arr::Edge_iterator Edge_iterator;
  typedef Curve_pol_data Data;
  typedef Pol_halfedge           Halfedge;
  typedef  Pol_face_iterator    Face_iterator;

  //point location
  typedef Pol_trap_point_location      Trap_point_location;
  typedef Pol_naive_point_location     Naive_point_location;
  typedef Pol_simple_point_location    Simple_point_location;
  typedef Pol_walk_point_location      Walk_point_location;
  //typedef Pol_lenmarks_point_location  Lenmarks_point_location;
 

  /*! coordinate scale - used in conics*/
  int COORD_SCALE;
  
  /*! constructor */
  Polyline_tab_traits():
  COORD_SCALE(1)
  {}
  
  /*! distructor */
  ~Polyline_tab_traits()
  {}

 
  /*! curve_has_same_direction - return true if the curve and
   *  the halfedge has the same direction
   */
  bool curve_has_same_direction( Ccb_halfedge_circulator &cc)
  {
    return ( *(cc->curve().begin()) == cc->source()->point());
  }

  /*!
   */
  bool is_curve_and_halfedge_same_direction(const Halfedge_handle & he,
                                            const Xcurve & cv)
  {
    return (he->source()->point() == *(cv.begin()));
  }

  /*! fill_face - fill a face with its color (which is stored at the curves)
   * it creates a polyong from the outer boundary of the face and 
   * uses CGAL opertaor << of polygons 
   */
  void fill_face(Qt_widget_demo_tab<Polyline_tab_traits> * w , Face_handle f)
  {
    if (f->does_outer_ccb_exist())  // f is not the unbounded face
    {
      std::list< Coord_point > pts; // holds the points of the polygon
      Xcurve::const_iterator   pt_itr;
      Xcurve cv;

      /* running with around the outer of the face and generate from it
       * polygon
       */
      Ccb_halfedge_circulator cc=f->outer_ccb();
      do {
        cv = cc->curve();
        if( curve_has_same_direction (cc) )
        {
          for( pt_itr = cv.begin() , ++pt_itr ; pt_itr != cv.end(); ++pt_itr)
          {
            Coord_type x = CGAL::to_double((*pt_itr).x());
            Coord_type y = CGAL::to_double((*pt_itr).y());
            Coord_point coord_source(x , y);
            pts.push_back(coord_source );
          }
        }
        else
        {
          for( pt_itr = cv.rbegin() , ++pt_itr ; pt_itr != cv.rend();
               ++pt_itr)
          {
            Coord_type x = CGAL::to_double((*pt_itr).x());
            Coord_type y = CGAL::to_double((*pt_itr).y());
            Coord_point coord_source(x , y);
            pts.push_back(coord_source );
          }
        }
        //created from the outer boundary of the face
      } while (++cc != f->outer_ccb());

      // make polygon from the outer ccb of the face 'f'
      Polygon pgn (pts.begin() , pts.end());

      w->setFilled(true);

      // fill the face according to its color (stored at any of her
      // incidents curves)
      if (! f->info().isValid())
        w->setFillColor(def_bg_color);
      else
        w->setFillColor(f->info());
      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);

      (*w) << pgn ;  // draw the polyong 
      w->setFilled(false);  
      w->get_painter().setPen(old_penstyle);
    }
    else
    {
      Coord_point points[4];
      points[0] = (Coord_point(w->x_min(),w->y_min()));
      points[1] = (Coord_point(w->x_min(),w->y_max()));
      points[2] = (Coord_point(w->x_max(),w->y_max()));
      points[3] = (Coord_point(w->x_max(),w->y_min()));
     
      w->setFilled(true);
      w->setFillColor(w->unbounded_face_color());
      
      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);
      (*w)<<Polygon(points , points +4 );
      w->setFilled(false);
       w->get_painter().setPen(old_penstyle);
    }
  }
  
  /*! draw_xcurve - go over the polyline parts and use Qt_Widget operator
   * to draw
   */
  void draw_xcurve(Qt_widget_demo_tab<Polyline_tab_traits> * w , Xcurve pol )
  {
    Curve::const_iterator ps = pol.begin();
    Curve::const_iterator pt = ps; pt++;
    
    while (pt != pol.end()) {
      const Pm_point_2 & source = *ps;
      const Pm_point_2 & target = *pt;
      Coord_segment coord_seg = convert(source , target);
      *w << coord_seg;
      ps++; pt++;
    }
    
  }
  
  /*! first_point - a first point of inserted polyline or a splitter
   */
  void first_point( Coord_point p , Mode m)
  {
    last_of_poly = p;
    if (m == INSERT)
      points.push_back(Pm_pol_point_2(p.x(),p.y()));    
  }
  
  /*! middle_point - a middle point of a polyline
   */
  void middle_point( Coord_point p ,
                     Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    if (last_of_poly == p) return;
    rubber_old = p;
    
    points.push_back(Pm_pol_point_2(p.x(),p.y()));    
    
    *w << CGAL::WHITE;
    *w << Coord_segment(rubber, last_of_poly);
    *w << CGAL::GREEN;
    *w << Coord_segment(rubber, last_of_poly);
    
    last_of_poly = p;
  }
  
  /*! last_point - last point of the polyline, create new 
   * polyline and reset 
   */
  void last_point( Coord_point p ,Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    get_polyline(w);
    points.clear();
    w->active = false;
    w->first_time = true;
    //w->redraw();  // not working so I use new_object insted
    w->new_object(make_object(Coord_segment(p , p)));
  }
  
  /*! curve_point_distance - return the distance between a point
   * and a polyline
   */
  Coord_type curve_point_distance(Coord_point p, Curve * c ,
                                  Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    Curve_const_iterator ps = c->begin();
    Curve_const_iterator pt = ps; pt++;
    bool first = true;
    Coord_type min_dist = 0;
    while (pt != c->end()) {
      const Pm_point_2 & source = *ps;
      const Pm_point_2 & target = *pt;
      Coord_segment coord_seg = convert(source , target);
      Coord_type dist = CGAL::squared_distance( p, coord_seg);
      if( dist < min_dist || first)
      {
        first = false;
        min_dist = dist;
      }
      ps++; pt++;
    }
    return min_dist;
  }
  
  /*! xcurve_point_distance - return the distance between a point
   * and a polyline
   */
  Coord_type xcurve_point_distance(Coord_point p, Xcurve & c,
                                   Qt_widget_demo_tab<Polyline_tab_traits> *
                                   w)
  {
    Curve_const_iterator ps = c.begin();
    Curve_const_iterator pt = ps; pt++;
    bool first = true;
    Coord_type min_dist = 0;
    while (pt != c.end()) {
      const Pm_point_2 & source = *ps;
      const Pm_point_2 & target = *pt;
      Coord_segment coord_seg = convert(source , target);
      Coord_type dist = CGAL::squared_distance( p, coord_seg);
      if( dist < min_dist || first)
      {
        first = false;
        min_dist = dist;
      }
      ps++; pt++;
    }
    return min_dist;
  }
  
  /*! draw_last_segment - call from mouse move event
   */
  void draw_last_segment( Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    *w << Coord_segment(rubber_old, last_of_poly);
  }
  
  /*! draw_current_segment - call from mouse move event */
  void draw_current_segment( Coord_point p ,
                             Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    *w << Coord_segment(p, last_of_poly);
    rubber = p;
    rubber_old = p;
  }
  
  /*! closest_point - find the closest point in the planar map
   * to a clicked point
   */
  Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest,
                           Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    bool first = true;
    Coord_type x1,y1,dt,min_dist = 0;
    Halfedge_iterator heit;
    for (heit = w->m_curves_arr->halfedges_begin();
         heit != w->m_curves_arr->halfedges_end(); heit++)
    {
      const Xcurve& curve = heit->curve();
      Curve_const_iterator cit;
      for (cit = curve.begin(); cit != curve.end(); cit++)
      {
        const Pm_point_2& p = *cit;
        x1 = CGAL::to_double(p.x());
        y1 = CGAL::to_double(p.y());
        dt = w->dist(x1 , y1 , x , y);
        if ( dt < min_dist || first)
        {
          min_dist = dt;
          closest = Coord_point(x1 , y1);
          first = false;
        }
      }
    }
    Point_vector_iterator it;
    for (it = points.begin(); it != points.end(); it++)
    {
      const Pm_pol_point_2& p = *it;
      x1 = CGAL::to_double(p.x());
      y1 = CGAL::to_double(p.y());
      dt = w->dist(x1 , y1 , x , y);
      if ( dt < min_dist || first)
      {
        min_dist = dt;
        closest = Coord_point(x1 , y1);
        first = false;
      }
    }
    return min_dist;
  }
  
  /*! get_origin_curve - return the origin base curve
   */
  const Pm_base_pol_2* get_origin_curve(const Pm_xpol_2 & xseg )
  {
    const Curve_pol_data & curve_data = xseg.get_data();
    if (curve_data.m_type == Curve_pol_data::LEAF) 
      return curve_data.m_ptr.m_curve;
    else // curve_data.m_type == Curve_data::INTERNAL
    {
      const Pm_xpol_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve;        
      return get_origin_curve( *xseg_p );
    }
  }

  /*! curve_make_x_monotone
   */
  const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2)
  {
    std::vector<Pm_pol_point_2> temp_points;
    temp_points.push_back(p1);
    temp_points.push_back(p2);
    Data d;
    Curve cv(Base_curve(temp_points.begin(), temp_points.end() ) , d);
    std::list<Xcurve> xcurve_list;
    m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list));
    const Xcurve c1 = xcurve_list.front();
    return c1;
  }
 
  /*!
   */
  void find_close_curve(Halfedge_iterator & closest_curve,
                        Halfedge_iterator & second_curve, Coord_point & p,
                        Qt_widget_demo_tab<Polyline_tab_traits> * w,
                        bool move_event)
  {
    bool is_first = true;
    Coord_type min_dist = 0;

    Halfedge_iterator hei;
    Pm_point_2 s;
    Pm_point_2 t;
    Vertex_iterator   vis;
    Vertex_iterator   vit;

    if (closest_curve->source()->point() == *(closest_curve->curve().begin()))
    {
      vis = closest_curve->source();
      vit = closest_curve->target();
    }
    else
    {
      vit = closest_curve->source();
      vis = closest_curve->target();
    }
    s = *(closest_curve->curve().begin());
    t = *(closest_curve->curve().rbegin());

    for (hei = w->m_curves_arr->halfedges_begin();
         hei != w->m_curves_arr->halfedges_end(); ++hei) 
    {
      Pm_point_2 s1 = *(hei->curve().begin());
      Pm_point_2 t1 = *(hei->curve().rbegin());

      if (merge_segments_precondition<Pm_point_2>(s, t, s1, t1,
                                                  vis->degree(),
                                                  vit->degree()))
      {
        Xcurve & xcurve = hei->curve();
        Coord_type dist = xcurve_point_distance( p, xcurve , w);
        if (is_first || dist < min_dist)
        {
          min_dist = dist;
          second_curve = hei;
          is_first = false;
        }    
      }
    }
    if (is_first) // didn't find any "good" curve
      return;
    else if (!move_event)
    {
      Xcurve & c = closest_curve->curve();
      Xcurve & c1 = second_curve->curve();

      Pm_point_2 s1 = *(second_curve->curve().begin());
      Pm_point_2 t1 = *(second_curve->curve().rbegin());
      std::vector<Pm_pol_point_2> temp_points;
      Curve_const_iterator cit;
 
      if (t == s1 || t == t1)
      {
        for (cit = c.begin(); cit != c.end(); cit++)
        {
          temp_points.push_back(*cit);
        }
      }
      else
      {
        for (cit = c.rbegin(); cit != c.rend(); cit++)
        {
          temp_points.push_back(*cit);
        }
      }
      Kernel ker;
      if (ker.compare_slope_2_object()(Kernel::Segment_2 (s, t),
                                       Kernel::Segment_2 (s1, t1)) ==
          CGAL::EQUAL)
      {
        temp_points.pop_back();
      }

      if (s1 == s || s1 == t)
      {
        cit = c1.begin(), cit++;
        for ( ; cit != c1.end(); cit++)
        {
          temp_points.push_back(*cit);
        }
      }
      else
      {
        cit = c1.rbegin(), cit++;
        for (; cit != c1.rend(); cit++)
        {
          temp_points.push_back(*cit);
        }
      }

      Base_curve *base = new Base_curve(temp_points.begin(),
                                        temp_points.end());
      Curve_pol_data cd;
      cd.m_type = Curve_pol_data::LEAF;
      cd.m_index = w->index;
      cd.m_ptr.m_curve = base;
      Curve *curve = new Curve( *base, cd );
      std::list<Xcurve> xcurve_list;
      m_traits.curve_make_x_monotone(*curve, std::back_inserter(xcurve_list));
      Xcurve cc = xcurve_list.front();
      Halfedge_handle h = w->m_curves_arr->merge_edge(closest_curve ,
                                                      second_curve, cc); 
      w->update_curve_data_after_merge(h , cc);
    }
  }

  /*!
   */
  void split_edge(Halfedge_iterator &hei ,Pm_point_2 &p ,
                  Qt_widget_demo_tab<Polyline_tab_traits> *w)
  {
    Base_curve *base1 = new Base_curve;
    Base_curve *base2 = new Base_curve;

    Base_pol_traits  base_pol_traits;

    base_pol_traits.curve_split (hei->curve(), *base1, *base2, p);

    std::list<Xcurve> xcurve_list;

    //Base_curve *base1 = new Base_curve(temp_points1.begin(),
    // temp_points1.end());
    Curve_pol_data cd1;
    cd1.m_type = Curve_pol_data::LEAF;
    cd1.m_index = hei->curve().get_data().m_index;
    cd1.m_ptr.m_curve = base1;
    Curve *seg1 = new Curve( *base1, cd1 );
    m_traits.curve_make_x_monotone(*seg1, std::back_inserter(xcurve_list));
    Xcurve c1 = xcurve_list.front();

    xcurve_list.clear();

    // Base_curve *base2 = new Base_curve(temp_points2.begin(),
    // temp_points2.end());
    Curve_pol_data cd2;
    cd2.m_type = Curve_pol_data::LEAF;
    cd2.m_index = hei->curve().get_data().m_index;
    cd2.m_ptr.m_curve = base2;
    Curve *seg2 = new Curve( *base2, cd2 );
    m_traits.curve_make_x_monotone(*seg2, std::back_inserter(xcurve_list));
    Xcurve c2 = xcurve_list.front();
    Halfedge_handle e1 = w->m_curves_arr->split_edge(hei , c1 , c2);

    w->update_curves_date_after_split(e1 , c1, c2);
  }

private:
  
  /*! get_polyline - create a new polyline
   */
  void get_polyline(Qt_widget_demo_tab<Polyline_tab_traits> * w)
  {
    Pol_notification pol_notif;
    Pm_base_pol_2 * base_pol_p =
      new Pm_base_pol_2(points.begin(), points.end());
    Curve_pol_data cd;
    cd.m_type = Curve_pol_data::LEAF;
    cd.m_index = w->index;
    cd.m_ptr.m_curve = base_pol_p;
    Curve * pol = new Curve( *base_pol_p, cd );
    w->m_curves_arr->insert( *pol , &pol_notif);
    CGAL::Bbox_2 curve_bbox = pol->bbox();
    w->bbox = w->bbox + curve_bbox;
  }
  
  /*! convert - convert from Pm_pol_curve to Coord_segment
   */
  Coord_segment convert(Pm_pol_point_2 & source , Pm_pol_point_2 & target)
  {
    Coord_type x1 = CGAL::to_double(source.x());
    Coord_type y1 = CGAL::to_double(source.y());
    Coord_point coord_source(x1, y1);
    
    Coord_type x2 = CGAL::to_double(target.x());
    Coord_type y2 = CGAL::to_double(target.y());
    Coord_point coord_target(x2, y2);
    
    return Coord_segment(coord_source, coord_target);
  }
  
  /*! convert - convert from const Pm_pol_curve to Coord_segment
   */
  Coord_segment convert(const Pm_pol_point_2 & source ,
                        const Pm_pol_point_2 & target)
  {
    Coord_type x1 = CGAL::to_double(source.x());
    Coord_type y1 = CGAL::to_double(source.y());
    Coord_point coord_source(x1, y1);
    
    Coord_type x2 = CGAL::to_double(target.x());
    Coord_type y2 = CGAL::to_double(target.y());
    Coord_point coord_target(x2, y2);
    
    return Coord_segment(coord_source, coord_target);
  }
  
  Traits m_traits;

  /*! the new point of the rubber band */
  Coord_point rubber;

  /*! the last point of the polygon */
  Coord_point last_of_poly;

  /*! the old point of the rubber band */
  Coord_point rubber_old;

  /*! container to hold the point during polyline creation */
  std::vector<Pm_pol_point_2> points;  
};

//////////////////////////////////////////////////////////////////////////////
/*!
 */
class Conic_tab_traits
{
public:
  typedef Pm_xconic_list Curves_list;
  typedef Conic_arr Curves_arr;
  typedef Conic_traits Traits;
  typedef Pm_xconic_iter Pm_curve_iter;
  typedef Pm_xconic_const_iter Pm_curve_const_iter;
  typedef Conic_locate_type Locate_type;
  typedef Pm_conic_point_2 Pm_point_2;
  typedef Conic_halfedge_handle Halfedge_handle;
  typedef Pm_xconic_2 Curve;
  typedef Pm_xconic_2 Xcurve;
  typedef Pm_base_conic_2 Base_curve;
  typedef Conic_face_handle Face_handle;
  typedef Conic_ccb_halfedge_circulator Ccb_halfedge_circulator;
  typedef Conic_holes_iterator Holes_iterator;
  typedef Conic_pm::Halfedge_iterator Halfedge_iterator;
  typedef std::list<Halfedge_iterator> Hafledge_list;
  typedef Hafledge_list::iterator Hafledge_list_iterator;
  typedef Conic_pm Pm;
  typedef Curves_arr::Vertex_iterator Vertex_iterator;
  typedef Curves_arr::Halfedge_around_vertex_circulator
  Halfedge_around_vertex_circulator;
  typedef Curves_arr::Edge_iterator Edge_iterator;
  typedef Curve_conic_data Data;
  typedef Conic_halfedge           Halfedge;
  typedef  Conic_face_iterator    Face_iterator;
  
  //point location
  typedef Conic_trap_point_location      Trap_point_location;
  typedef Conic_naive_point_location     Naive_point_location;
  typedef Conic_simple_point_location    Simple_point_location;
  typedef Conic_walk_point_location      Walk_point_location;
  //typedef Conic_lenmarks_point_location  Lenmarks_point_location;
 
  /*! coordinate scale - used in conics*/
  int COORD_SCALE;
  int DRAW_FACTOR;

  /*! constructor */
  Conic_tab_traits():
  COORD_SCALE(1),
  DRAW_FACTOR(5)
  {}
  
  /*! distructor */
  ~Conic_tab_traits()
  {}

  /*! curve_has_same_direction - return true if the curve and
   *  the halfedge has the same direction
   */
  bool curve_has_same_direction( Ccb_halfedge_circulator &cc)
  {
    return (cc->curve().source() == cc->source()->point());
  }

  /*! check if curve and its halfedge are at the same direction
   */
  bool is_curve_and_halfedge_same_direction(const Halfedge_handle & he,
                                            const Xcurve & cv)
  {
    return (he->source()->point() == cv.source());
  }

  /*!
   */
  void fill_face(Qt_widget_demo_tab<Conic_tab_traits> * w , Face_handle f)
  {
    if (f->does_outer_ccb_exist())  // f is not the unbounded face
    {
      std::list< Coord_point > pts; // holds the points of the polygon         
      /* running with around the outer of the face and generate from it
       * polygon
       */
      Ccb_halfedge_circulator cc=f->outer_ccb();
      do {
        if(w->antenna(*cc))
          continue;
        Xcurve c = cc->curve(); 
        // Get the co-ordinates of the curve's source and target.
        double sx = CGAL::to_double(cc->source()->point().x()),
               sy = CGAL::to_double(cc->source()->point().y()),
               tx = CGAL::to_double(cc->target()->point().x()),
               ty = CGAL::to_double(cc->target()->point().y());
        
        Coord_point coord_source(sx / COORD_SCALE, sy / COORD_SCALE);
        Coord_point coord_target(tx / COORD_SCALE, ty / COORD_SCALE);

        if (c.is_segment())
            pts.push_back(coord_source ); 
        else
        {
          // If the curve is monotone, than its source and its target has the
          // extreme x co-ordinates on this curve.
          if (c.is_x_monotone())
          {
            
            bool     is_source_left = (sx < tx);
            int      x_min = is_source_left ? (*w).x_pixel(sx) : 
                                              (*w).x_pixel(tx);
            int      x_max = is_source_left ? (*w).x_pixel(tx) :
                                              (*w).x_pixel(sx);
            double   curr_x, curr_y;
            int      x;
  
            Pm_conic_point_2 ps[2];
            int nps;

            pts.push_back(coord_source ); 

            if (is_source_left)
            {
              for (x = x_min + DRAW_FACTOR; x < x_max; x+=DRAW_FACTOR)
                //= COORD_SCALE)
              {
                curr_x = (*w).x_real(x);
                nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps);
                if (nps == 1)
                {
                  curr_y = CGAL::to_double(ps[0].y());
                  pts.push_back(Coord_point(curr_x / COORD_SCALE,
                                            curr_y / COORD_SCALE));
                }// if
              }// for            
            }
            else
            {              
              for (x = x_max; x > x_min; x-=DRAW_FACTOR)
              {
                curr_x = (*w).x_real(x);
                nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps);
                if (nps == 1)
                {
                  curr_y = CGAL::to_double(ps[0].y());
                  pts.push_back(Coord_point(curr_x / COORD_SCALE,
                                            curr_y / COORD_SCALE));
                }// if
              }// for       
            }// else
            pts.push_back(coord_target ); 
          }// if
          else
          {
            // We should never reach here.
            CGAL_assertion(false);
          }// else
        }// else
        //created from the outer boundary of the face
      } while (++cc != f->outer_ccb());

       // make polygon from the outer ccb of the face 'f'
      Polygon pgn (pts.begin() , pts.end());
      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);
      w->setFilled(true);

      // fill the face according to its color (stored at any of her incidents
      // curves)
      if (! f->info().isValid())
        w->setFillColor(def_bg_color);
      else
        w->setFillColor(f->info());

      (*w) << pgn ;  // draw the polyong 
      w->get_painter().setPen(old_penstyle);
      w->setFilled(false);
    }
    else
    {
      Coord_point points[4];
      points[0] = (Coord_point(w->x_min(),w->y_min()));
      points[1] = (Coord_point(w->x_min(),w->y_max()));
      points[2] = (Coord_point(w->x_max(),w->y_max()));
      points[3] = (Coord_point(w->x_max(),w->y_min()));
     
      w->setFilled(true);
      w->setFillColor(w->unbounded_face_color());
      
      QPen old_penstyle = w->get_painter().pen();
      w->get_painter().setPen(Qt::NoPen);
      (*w)<<Polygon(points , points +4 );
      w->setFilled(false);
       w->get_painter().setPen(old_penstyle);
    }
  }
   
  /*! draw_xcurve - same as draw_curve
   */
  void draw_xcurve(Qt_widget_demo_tab<Conic_tab_traits> * w , Xcurve c )
  {
    // Get the co-ordinates of the curve's source and target.
    double sx = CGAL::to_double(c.source().x()),
      sy = CGAL::to_double(c.source().y()),
      tx = CGAL::to_double(c.target().x()),
      ty = CGAL::to_double(c.target().y());
    
    if (c.is_segment())
    {
      Coord_point coord_source(sx / COORD_SCALE, sy / COORD_SCALE);
      Coord_point coord_target(tx / COORD_SCALE, ty / COORD_SCALE);
      Coord_segment coord_seg(coord_source, coord_target);
      
      *w << coord_seg;
    }
    else
    {
      // If the curve is monotone, than its source and its target has the
      // extreme x co-ordinates on this curve.
      if (c.is_x_monotone())
      {
        
        bool     is_source_left = (sx < tx);
        int      x_min = is_source_left ? (*w).x_pixel(sx) : 
          (*w).x_pixel(tx);
        int      x_max = is_source_left ? (*w).x_pixel(tx) :
          (*w).x_pixel(sx);
        double   prev_x = is_source_left ? sx : tx;
        double   prev_y = is_source_left ? sy : ty;
        double   end_x = is_source_left ? tx : sx;
        double   end_y = is_source_left ? ty : sy;
        double   curr_x, curr_y;
        int      x;
        
        Pm_conic_point_2 ps[2];
        int nps;
        
        for (x = x_min + DRAW_FACTOR; x < x_max; x+=DRAW_FACTOR)
        {
          curr_x = (*w).x_real(x);
          nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps);
          if (nps == 1)
          {
            curr_y = CGAL::to_double(ps[0].y());
            (*w) << Coord_segment (Coord_point(prev_x / COORD_SCALE,
                                               prev_y / COORD_SCALE),
                                   Coord_point(curr_x / COORD_SCALE,
                                               curr_y / COORD_SCALE));
            prev_x = curr_x;
            prev_y = curr_y;
            
          }
        }
        
        (*w) << Coord_segment (Coord_point(prev_x / COORD_SCALE,
                                           prev_y / COORD_SCALE),
                               Coord_point(end_x / COORD_SCALE,
                                           end_y / COORD_SCALE));
      }
      else
      {
        // We should never reach here.
        CGAL_assertion(false);
      }
    }
  }
  
  /*! get_origin_curve - return the origin base curve
   */
  const Pm_base_conic_2* get_origin_curve(const Pm_xconic_2 & xseg )
  {
    const Curve_conic_data & curve_data = xseg.get_data();
    if (curve_data.m_type == Curve_conic_data::LEAF) 
      return curve_data.m_ptr.m_curve;
    else // curve_data.m_type == Curve_data::INTERNAL
    {
      Pm_xconic_2* xseg_p = curve_data.m_ptr.m_x_motonote_curve;        
      return get_origin_curve( *xseg_p );
    }
  }
  
  ////////////////////////////////////////////////////////////////////////////
  
  /*! first_point - a first point of inserted sgment
   */
  void first_point( Coord_point p , Mode m)
  {
    m_p_old = m_p1 = m_p2 = m_p3 = m_p4 = p;
    num_points = 1;
    first_time = true;
  }
  
  /*! middle_point - the last point of a segment
   */
  void middle_point( Coord_point p , Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    CfNT r, s, t, u, v, ww;  // The conic coefficients.
    CfNT a, b, c, a_sq, b_sq;
    CfNT x, y, x1, y1, x0, y0, temp;
    CfNT sq_rad;

    x1 = CfNT(static_cast<int>(COORD_SCALE * m_p1.x()));
    y1 = CfNT(static_cast<int>(COORD_SCALE * m_p1.y()));
    x = CfNT(static_cast<int>(COORD_SCALE * p.x()));
    y = CfNT(static_cast<int>(COORD_SCALE * p.y()));

    if(x != x1 || y != y1) 
    {      
      Pm_base_conic_2 *cv = NULL;

      switch (w->conic_type)
      {
       case CIRCLE:
        sq_rad = CGAL::square(x - x1) + CGAL::square(y - y1);
        cv = new Pm_base_conic_2(Int_circle_2 (Int_point_2(x1, y1), sq_rad)); 
        break;

       case SEGMENT:
        cv = new Pm_base_conic_2(Int_segment_2 (Int_point_2(x,y),
                                                Int_point_2(x1,y1)));
        break;

       case ELLIPSE:
        if (y == y1 || x == x1)
        {
          QMessageBox::information( w, "Insert Ellipse", "Invalid Ellipse");
          w->active = false;
          return;
        }

        a = CORE::abs(x1 - x)/2;
        b = CORE::abs(y1 - y)/2;
        a_sq = a*a;
        b_sq = b*b;
        x0 = (x + x1)/2;
        y0 = (y + y1)/2;
        
        r = b_sq;
        s = a_sq;
        t = 0;
        u = -2*x0*b_sq;
        v = -2*y0*a_sq;
        ww = x0*x0*b_sq + y0*y0*a_sq - a_sq*b_sq;

        cv = new Pm_base_conic_2(r, s, t, u, v, ww);
        break;

        // RWRW: Do nothing ...
       case PARABOLA:
        *w << CGAL::LineWidth(3);
        if (num_points == 1)
        {
          m_p2 = p;
          num_points++;
          *w << m_p2;
          return;
        }
        if (num_points == 2)
        {
          CfNT x2 = CfNT(static_cast<int>(COORD_SCALE * m_p2.x()));
          CfNT y2 = CfNT(static_cast<int>(COORD_SCALE * m_p2.y()));
          Int_kernel ker;
          // the three points of the parabola cannot be collinear (
          if (ker.collinear_2_object()(Int_point_2(x1,y1),
                                       Int_point_2(x,y),Int_point_2(x2,y2)))
          {
            QMessageBox::information( w, "Insert Conic", "Invalid Conic");
            w->active = false;
            *w << m_p1 << m_p2 ;
            return; 
          }
          cv = new Pm_base_conic_2 (Int_point_2(x1,y1),Int_point_2(x2,y2),
                                    Int_point_2(x,y));
        }
        break;

       case HYPERBOLA:
        *w << CGAL::LineWidth(3);
        if (num_points == 1)
        {
          m_p2 = p;
          num_points++;
          *w << m_p2;
          return;
        }
        if (num_points == 2)
        {
          m_p3 = p;
          num_points++;
          *w << m_p3;
          return;
        }
        if (num_points == 3)
        {
          m_p4 = p;
          num_points++;
          *w << m_p4;
          return;
        }
        if (num_points == 4)
        { 
          *w << p;
          CfNT x2 = CfNT(static_cast<int>(COORD_SCALE * m_p2.x()));
          CfNT y2 = CfNT(static_cast<int>(COORD_SCALE * m_p2.y()));
          CfNT x3 = CfNT(static_cast<int>(COORD_SCALE * m_p3.x()));
          CfNT y3 = CfNT(static_cast<int>(COORD_SCALE * m_p3.y()));
          CfNT x4 = CfNT(static_cast<int>(COORD_SCALE * m_p4.x()));
          CfNT y4 = CfNT(static_cast<int>(COORD_SCALE * m_p4.y()));
          cv = new Pm_base_conic_2 (Int_point_2(x1,y1),Int_point_2(x2,y2),
                                    Int_point_2(x3,y3),Int_point_2(x4,y4),
                                    Int_point_2(x,y));
          if (! cv->is_valid())
          {
            QMessageBox::information( w, "Insert Conic", "Invalid Conic");
            w->active = false;
            *w << m_p1 << m_p2 << m_p3 << m_p4 << p;
            return;
          }
        }
        break;
      }
      Curve_conic_data cd;
      cd.m_type = Curve_conic_data::LEAF;
      cd.m_index = w->index;
      cd.m_ptr.m_curve = cv;
      Conic_notification conic_notif;
      w->m_curves_arr->insert(Pm_conic_2( *cv , cd), & conic_notif);
      CGAL::Bbox_2 curve_bbox = cv->bbox();
      w->bbox = w->bbox + curve_bbox; 
      w->active = false;
      //w->redraw();  // not working so I use new_object insted
      w->new_object(make_object(Coord_segment(m_p1 , p)));
    } 
  }
  
  /*! last_point - meaningless for conics - at least for now
   */
  void last_point( Coord_point p , Qt_widget_demo_tab<Conic_tab_traits> * w )
  {   
    return;
  }

  /*! draw_last_segment - call from mouse move event
   */
  void draw_last_segment( Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    if (w->mode == SPLIT)
      *w << Coord_segment( m_p1 , m_p_old );
    else
    {
      switch (w->conic_type)
      {
       case CIRCLE:
        *w << Coord_circle(m_p1,
                           pow(m_p1.x() - m_p_old.x(), 2) +
                           pow(m_p1.y() - m_p_old.y(),2));
        break;
       case SEGMENT:
        *w << Coord_segment( m_p1 , m_p_old );
        break;
       case ELLIPSE:
        {
         *w << Coord_segment( Coord_point(m_p1.x(),m_p_old.y()) , m_p_old );
         *w << Coord_segment( Coord_point(m_p1.x(),m_p_old.y()) , m_p1 );
         *w << Coord_segment( Coord_point(m_p_old.x(),m_p1.y()) , m_p_old );
         *w << Coord_segment( Coord_point(m_p_old.x(),m_p1.y()) , m_p1 );
         break;
        }
       case PARABOLA:
        if (first_time)
        {
          *w << CGAL::LineWidth(3);
          *w << m_p1;
          first_time = false;
        }
        break;
       case HYPERBOLA:
        if (first_time)
        {
          *w << CGAL::LineWidth(3);
          *w << m_p1;
          first_time = false;
        }
        break;
      }
    }
  }
  
  /*! draw_current_segment - call from mouse move event
   */
  void draw_current_segment( Coord_point p ,
                             Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    m_p_old = p;
    draw_last_segment(w);
  }

  /*! closest_point - find the closest point in the planar map
   * to a clicked point
   */
  Coord_type closest_point(Coord_type x, Coord_type y, Coord_point &closest,
                           Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    bool first = true;
    Coord_type x1,y1,dt,min_dist = 0;
    //Coord_type x_scale = COORD_SCALE * x;
    //Coord_type y_scale = COORD_SCALE * y;
    Vertex_iterator vit;
    for (vit = w->m_curves_arr->vertices_begin();
         vit != w->m_curves_arr->vertices_end(); vit++)
    {
      const Pm_point_2& p = (*vit).point();
      x1 = CGAL::to_double(p.x()) / COORD_SCALE;
      y1 = CGAL::to_double(p.y()) / COORD_SCALE;
      dt = w->dist(x1 , y1 , x , y);
      if ( dt < min_dist || first)
      {
        min_dist = dt;
        closest = Coord_point(x1 , y1);
        first = false;
      }
    }
    return min_dist;
  }
  
  /*! curve_point_distance - return the distance between 
   * a point and a conic
   */
  Coord_type curve_point_distance(Coord_point p, Curve * c ,
                                  Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    // Get the co-ordinates of the curve's source and target.
    double sx = CGAL::to_double(c->source().x()),
      sy = CGAL::to_double(c->source().y()),
      tx = CGAL::to_double(c->target().x()),
      ty = CGAL::to_double(c->target().y());
    
    if (c->is_segment())
    {
      Coord_point coord_source(sx , sy);
      Coord_point coord_target(tx , ty);
      Coord_segment coord_seg(coord_source, coord_target);
      
      return CGAL::squared_distance( p, coord_seg);
    }
    else
    {
      // If the curve is monotone, than its source and its target has the
      // extreme x co-ordinates on this curve.
      if (c->is_x_monotone())
      {
        
        bool     is_source_left = (sx < tx);
        int      x_min = is_source_left ? (*w).x_pixel(sx) : 
          (*w).x_pixel(tx);
        int      x_max = is_source_left ? (*w).x_pixel(tx) :
          (*w).x_pixel(sx);
        double   prev_x = is_source_left ? sx : tx;
        double   prev_y = is_source_left ? sy : ty;
        //double   end_x = is_source_left ? tx : sx;
        //double   end_y = is_source_left ? ty : sy;
        double   curr_x, curr_y;
        int      x;
        
        Pm_conic_point_2 ps[2];
        int nps;
        
        bool first = true;
        Coord_type min_dist = 0;
        
        
        for (x = x_min + 1; x < x_max; x++)
        {
          curr_x = (*w).x_real(x);
          nps = c->get_points_at_x(Pm_conic_point_2(curr_x, 0), ps);
          if (nps == 1)
          {
            curr_y = CGAL::to_double(ps[0].y());
            
            Coord_segment coord_seg( Coord_point(prev_x, prev_y) ,
                                     Coord_point(curr_x, curr_y) );
            Coord_type dist = CGAL::squared_distance( p, coord_seg);
            if( dist < min_dist || first)
            {
              first = false;
              min_dist = dist;
            }
            
            
            prev_x = curr_x;
            prev_y = curr_y;
            
          }
        }
        return min_dist;
      }// if is_x_monotone
      else
      {
        // We should never reach here.
        CGAL_assertion(false);
        return 0;
      }
    } // else 
  } // 

  /*! xcurve_point_distance - return the distance between
   * a point and a conic
   */
  Coord_type xcurve_point_distance(Coord_point p, Xcurve & c ,
                                   Qt_widget_demo_tab<Conic_tab_traits> * w)
  {
    // Get the co-ordinates of the curve's source and target.
    double sx = CGAL::to_double(c.source().x()),
      sy = CGAL::to_double(c.source().y()),
      tx = CGAL::to_double(c.target().x()),
      ty = CGAL::to_double(c.target().y());
    
    if (c.is_segment())
    {
      Coord_point coord_source(sx , sy);
      Coord_point coord_target(tx , ty);
      Coord_segment coord_seg(coord_source, coord_target);
      
      return CGAL::squared_distance( p, coord_seg);
    }
    else
    {
      // If the curve is monotone, than its source and its target has the
      // extreme x co-ordinates on this curve.
      if (c.is_x_monotone())
      {
        
        bool     is_source_left = (sx < tx);
        int      x_min = is_source_left ? (*w).x_pixel(sx) : 
          (*w).x_pixel(tx);
        int      x_max = is_source_left ? (*w).x_pixel(tx) :
          (*w).x_pixel(sx);
        double   prev_x = is_source_left ? sx : tx;
        double   prev_y = is_source_left ? sy : ty;
        double   curr_x, curr_y;
        int      x;
        
        Pm_conic_point_2 ps[2];
        int nps;
        
        bool first = true;
        Coord_type min_dist = 100000000;
        
        
        for (x = x_min + 1; x < x_max; x++)
        {
          curr_x = (*w).x_real(x);
          nps = c.get_points_at_x(Pm_conic_point_2(curr_x, 0), ps);
          if (nps == 1)
          {
            curr_y = CGAL::to_double(ps[0].y());
            
            Coord_segment coord_seg( Coord_point(prev_x, prev_y) ,
                                     Coord_point(curr_x, curr_y) );
            Coord_type dist = CGAL::squared_distance( p, coord_seg);
            if( dist < min_dist || first)
            {
              first = false;
              min_dist = dist;
            }
            
            
            prev_x = curr_x;
            prev_y = curr_y;
            
          }
        }
        return min_dist;
      }// if is_x_monotone
      else
      {
        // We should never reach here.
        CGAL_assertion(false);
        return 0;
      }
    } // else 
  } // 
  
  /*! curve_make_x_monotone
   */
  const Xcurve curve_make_x_monotone(Pm_point_2 p1 , Pm_point_2 p2)
  {
    /*! */
    Data d;

    // RWRW:
    Int_point_2          my_p1 (static_cast<int> (CGAL::to_double(p1.x())),
                                static_cast<int> (CGAL::to_double(p1.y())));
    Int_point_2          my_p2 (static_cast<int> (CGAL::to_double(p2.x())),
                                static_cast<int> (CGAL::to_double(p2.y())));
    Pm_base_conic_2 base (Int_segment_2 (my_p1, my_p2));
    // Pm_base_conic_2 base(Pm_conic_segment_2(p1 , p2));

    const Pm_conic_2 cv( base , d);
    std::list<Xcurve> xcurve_list;
    m_traits.curve_make_x_monotone(cv, std::back_inserter(xcurve_list));
    const Xcurve c1 = xcurve_list.front();
    return c1;
  }

  /*!
   */
  void find_close_curve(Halfedge_iterator & closest_curve,
                        Halfedge_iterator & second_curve, Coord_point & p,
                        Qt_widget_demo_tab<Conic_tab_traits> * w,
                        bool move_event)
  {
    bool is_first = true;
    Coord_type min_dist = 0;
    const Xcurve first = closest_curve->curve();
    Halfedge_iterator hei;
    Pm_point_2 s = closest_curve->curve().source();
    Pm_point_2 t = closest_curve->curve().target();
    Vertex_iterator   vis;
    Vertex_iterator   vit;
    if ( closest_curve->curve().source() == closest_curve->source()->point())
    {
      vis = closest_curve->source();
      vit = closest_curve->target();
    } 
    else
    {
      vit = closest_curve->source();
      vis = closest_curve->target();
    }
    for (hei = w->m_curves_arr->halfedges_begin();
         hei != w->m_curves_arr->halfedges_end(); ++hei) 
    {
      if (first.has_same_base_conic(hei->curve()))
      {
        Pm_point_2 s1 = hei->curve().source();
        Pm_point_2 t1 = hei->curve().target();

        if(  merge_segments_precondition<Pm_point_2>(s,t, s1,t1,
                                                     vis->degree(),
                                                     vit->degree()))
        { 
          Xcurve & xcurve = hei->curve();
          Coord_type dist = xcurve_point_distance( p, xcurve , w);
          if (is_first || dist < min_dist)
          {
            min_dist = dist;
            second_curve = hei;
            is_first = false;
          }    
        }
      }
    }
    if (is_first) // didn't find any "good" curve
      return;
    else if (!move_event)
    {
      Xcurve curve;
      const Xcurve second = second_curve->curve();

      m_traits.curve_merge (first, second, curve);

      Curve_conic_data cd1;
      cd1.m_type = Curve_conic_data::LEAF;
      cd1.m_index = first.get_data().m_index;
      cd1.m_ptr.m_curve = first.get_data().m_ptr.m_curve;

      Conic_notification conic_notif;

      // save the colors of the incident faces (to restore them later)
      QColor color1 = closest_curve->face()->info();
      QColor color2 = closest_curve->opposite()->face()->info();

      Pm_point_2 closest_curve_source = closest_curve->source()->point();
      Pm_point_2 closest_curve_target = closest_curve->target()->point();

      w->m_curves_arr->remove_edge(closest_curve);
      w->m_curves_arr->remove_edge(second_curve);

      Pm_conic_2 c( curve , cd1);
      Halfedge_handle h = w->m_curves_arr->insert(c );

      //restore the color of the incident faces of 'h'
      //check that 'closest_curev' and 'h' are at the dame direction
      if(closest_curve_source == h->source()->point() || 
         closest_curve_target == h->target()->point()    )
      {
        h->face()->set_info(color1);
        h->opposite()->face()->set_info(color2);
      }
      else  
      {
        h->face()->set_info(color2);
        h->opposite()->face()->set_info(color1);
      }

      Data d = c.get_data();
      if(is_curve_and_halfedge_same_direction(h , curve))
        d.halfedge_handle = h;
      else
        d.halfedge_handle = (Halfedge_handle)h->opposite();

      h->curve().set_data( d );
      h->opposite()->curve().set_data( d );
      
      //w->update_curve_data_after_merge(h , c);
      //// update c
      //
      // Curve_conic_data d = c.get_data();
      //d.halfedge_handle = h;
      
      //h->curve().set_data( d );
      //h->opposite()->curve().set_data( d );
    }
  }

  /*!
   */
  void split_edge(Halfedge_iterator &hei ,Pm_point_2 & p,
                  Qt_widget_demo_tab<Conic_tab_traits> * w)
  {    
    const Xcurve split_curve = hei->curve();
    Xcurve sbc1;
    Xcurve sbc2;
    
    m_traits.curve_split(split_curve , sbc1 , sbc2 , p);

    Curve_conic_data cd1;
    cd1.m_type = Curve_conic_data::LEAF;
    cd1.m_index = hei->curve().get_data().m_index;
    cd1.m_ptr.m_curve = hei->curve().get_data().m_ptr.m_curve;

    Pm_conic_2    sub_curve1 (sbc1, cd1);

    Curve_conic_data cd2;
    cd2.m_type = Curve_conic_data::LEAF;
    cd2.m_index = hei->curve().get_data().m_index;
    cd2.m_ptr.m_curve =hei->curve().get_data().m_ptr.m_curve;

    Pm_conic_2    sub_curve2 (sbc2, cd2);
    Conic_notification conic_notif;
    
    //  w->m_curves_arr->remove_edge(hei);
    Halfedge_handle h1 = w->m_curves_arr->insert(sub_curve1 , & conic_notif);
    Halfedge_handle h2 = w->m_curves_arr->insert(sub_curve2 , & conic_notif);

    // 
    // w->update_curves_date_after_split(hei , sub_curve1, sub_curve2);
    
    //// update data
    //
    // Curve_conic_data d1 = sub_curve1.get_data();
    //d1.halfedge_handle = h1;

    //h1->curve().set_data( d1 );
    //h1->opposite()->curve().set_data( d1 );

    // Curve_conic_data d2 = sub_curve2.get_data();
    //d2.halfedge_handle = h2;

    //h2->curve().set_data( d2 );
    //h2->opposite()->curve().set_data( d2 );
  }

  Traits m_traits;
  /*! temporary points of the created conic */
  Coord_point m_p_old,m_p1,m_p2,m_p3,m_p4;
  /*! bool flag for hyperbola insertion */
  bool first_time;
  /*! counter for the number of points */
  int num_points;
};

typedef Qt_widget_demo_tab<Segment_tab_traits> Qt_widget_segment_tab;
typedef Qt_widget_demo_tab<Polyline_tab_traits> Qt_widget_polyline_tab;
typedef Qt_widget_demo_tab<Conic_tab_traits> Qt_widget_conic_tab;

#endif //DEMO_TAB_H


syntax highlighted by Code2HTML, v. 0.9.1