
#ifndef _MDC_LINE_H_
#define _MDC_LINE_H_

#include "mdc_figure.h"


BEGIN_MDC_DECLS

class Connector;


enum LineEndType {
  NormalEnd,
  DashedNormalEnd,
  FilledTriangleEnd,
  HollowTriangleEnd,
  ChickenFootEnd,
  ChickenFoot0End,
  ChickenFoot1End,
  Cross0End,
  Cross1End,
  DashedChickenFootEnd,
  HollowDiamondEnd,
  FilledDiamondEnd,
  HollowCircleEnd,
  FilledCircleEnd,
  BoldStickEnd
};

enum LinePatternType {
  SolidPattern= 0,
  Dotted1Pattern,
  Dotted2Pattern,
  Dashed1Pattern,
  Dashed2Pattern,
  Dashed3Pattern,
  Dashed4Pattern,
  DashDot1Pattern,
  DashDot2Pattern,
  LastPattern
};



class Line;


class MYSQLCANVAS_PUBLIC_FUNC LineLayouter : public sigc::trackable
{
public:
  LineLayouter();
  virtual ~LineLayouter();

  sigc::signal<void> signal_changed() { return _changed; }

  virtual Connector* get_start_connector() const= 0;
  virtual Connector* get_end_connector() const= 0;

  virtual std::vector<Point> get_points()= 0;
  virtual Point get_start_point()= 0;
  virtual Point get_end_point()= 0;

  virtual std::vector<ItemHandle*> create_handles(Line *line, InteractionLayer *ilayer);
  virtual void update_handles(Line *line, std::vector<ItemHandle*> &handles);

  virtual bool handle_dragged(Line *line, ItemHandle *handle, const Point &pos, bool dragging);

  virtual void update()= 0;
protected:
  struct Segment
  {
    Point p1;
    Point p2;
  };

  sigc::signal<void> _changed;
};




class MYSQLCANVAS_PUBLIC_FUNC Line : public Figure
{
public:
  Line(Layer *layer, LineLayouter *layouter= 0);
  virtual ~Line();

  void set_layouter(LineLayouter *layouter);
  LineLayouter *get_layouter() { return _layouter; }

  virtual void resize_to(const Size &size);
  virtual void move_to(const Point &pos);

  virtual bool contains_point(const Point &point) const;
  
  virtual void draw_contents(CairoCtx *cr);
  virtual void stroke_outline(CairoCtx *cr, float offset= 0) const;

  void set_vertices(const std::vector<Point> &points);
  void add_vertex(const Point &pos);
  void set_vertex(size_t vertex, const Point &pos);
  inline Point get_vertex(size_t vertex) { return _vertices[vertex]; }
  size_t count_vertices() { return _vertices.size(); }


  void set_end_type(LineEndType start, LineEndType end);
  void set_line_pattern(LinePatternType pattern);

  void set_hops_crossings(bool flag);
  bool get_hops_crossings() const { return _hop_crossings; }

  virtual void mark_crossings(Line *line);
  
  virtual void create_handles(InteractionLayer *ilayer);
  virtual void update_handles();

  sigc::signal<void> signal_layout_changed() { return _layout_changed; }
protected:
  LineLayouter *_layouter;

  sigc::signal<void> _layout_changed;

  struct SegmentPoint
  {
    Point pos;
    Line *hop;

    SegmentPoint(const Point &p, Line *l) : pos(p), hop(l) {}
  };

  // the points that define the line
  std::vector<Point> _vertices;

  // the points that define the final appearance of the line (including intersections)
  std::vector<SegmentPoint> _segments;

  LineEndType _start_type;
  LineEndType _end_type;
  LinePatternType _line_pattern;

  bool _hop_crossings;

  void update_bounds();
  void update_layout();
  
  void set_line_pattern(CairoCtx *cr, LinePatternType pattern);
  
  double get_line_start_angle();
  double get_line_end_angle();

  void draw_line_ends(CairoCtx *cr);
  virtual void draw_outline_ring(CairoCtx *cr, const mdc::Color &color);
  
private:
  virtual bool on_drag_handle(ItemHandle *handle, const Point &pos, bool dragging);
};


END_MDC_DECLS

#endif /* _MDC_LINE_H_ */
