/* 
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */
#ifndef _FIGURE_COMMON_H_
#define _FIGURE_COMMON_H_

#include "mdc.h"

#include <algorithm>

#include "wbpublic_public_interface.h"
#include <grts/structs.model.h>

mdc::FontSpec parse_font_spec(const std::string &font);

namespace wbfig {

/** Abstract class to be overridden by diagram class which will receive events from various objects in canvas.
 */
class FigureEventHub
{
public:
  virtual bool figure_click(const model_ObjectRef &owner, mdc::CanvasItem *target, 
    const MySQL::Geometry::Point &point, mdc::MouseButton button, mdc::EventState state)= 0;
  virtual bool figure_double_click(const model_ObjectRef &owner, mdc::CanvasItem *target,
    const MySQL::Geometry::Point &point, mdc::MouseButton button, mdc::EventState state)= 0;
  virtual bool figure_button_press(const model_ObjectRef &owner, mdc::CanvasItem *target,
    const MySQL::Geometry::Point &point, mdc::MouseButton button, mdc::EventState state)= 0;
  virtual bool figure_button_release(const model_ObjectRef &owner, mdc::CanvasItem *target,
    const MySQL::Geometry::Point &point, mdc::MouseButton button, mdc::EventState state)= 0;
  virtual bool figure_enter(const model_ObjectRef &owner, mdc::CanvasItem *target,
    const MySQL::Geometry::Point &point)= 0;
  virtual bool figure_leave(const model_ObjectRef &owner, mdc::CanvasItem *target,
    const MySQL::Geometry::Point &point)= 0;
};

class BaseFigure;
  
class WBPUBLICBACKEND_PUBLIC_FUNC Titlebar : public mdc::Box
{
  typedef mdc::Box super;
public:
  Titlebar(mdc::Layer *layer, FigureEventHub *hub, BaseFigure *owner, bool expander);
  virtual ~Titlebar();

  void set_icon(cairo_surface_t *icon);
  void set_title(const std::string &text);
  
  inline const std::string &get_title() const { return _icon_text.get_text(); }

  void set_color(const MySQL::Drawing::Color &color);
  void set_text_color(const MySQL::Drawing::Color &color);
  void set_font(const mdc::FontSpec &font);
  const mdc::FontSpec &get_font() { return _icon_text.get_font(); }
  void set_rounded(mdc::CornerMask corners);
  void set_border_color(const MySQL::Drawing::Color &color);

  void set_expanded(bool flag);
  bool get_expanded();

  virtual void set_auto_sizing(bool flag);

  void auto_size() { _icon_text.auto_size(); }

  boost::signals2::signal<void (bool)>* signal_expand_toggle() { return &_signal_expand_toggle; }

protected:
  FigureEventHub *_hub;
  BaseFigure *_owner;

  mdc::IconTextFigure _icon_text;
  mdc::Button *_expander;

  MySQL::Drawing::Color _back_color;
  mdc::CornerMask _corners;
  MySQL::Drawing::Color _border_color;

  boost::signals2::signal<void (bool)> _signal_expand_toggle; 
  
  void expand_toggled();

  virtual void render(mdc::CairoCtx *cr);

  virtual bool on_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_double_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_press(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_release(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_enter(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  virtual bool on_leave(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
};


class WBPUBLICBACKEND_PUBLIC_FUNC CaptionFigure : public mdc::TextFigure
{
  typedef mdc::TextFigure super;
  
  FigureEventHub *_hub; 
  model_Object *_owner_object;

  virtual bool on_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_double_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_press(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_release(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_enter(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  virtual bool on_leave(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);

public:
  CaptionFigure(mdc::Layer *layer, FigureEventHub *hub, model_Object *owner);
};



class WBPUBLICBACKEND_PUBLIC_FUNC FigureItem : public mdc::IconTextFigure
{
  typedef mdc::IconTextFigure super;

  FigureEventHub *_hub; 
  BaseFigure *_owner;
  
  std::string _object_id;
  bool _dirty;

  virtual bool on_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_double_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_press(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_release(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_enter(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  virtual bool on_leave(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  
  virtual void draw_state(mdc::CairoCtx *cr);
  virtual MySQL::Geometry::Point get_intersection_with_line_to(const MySQL::Geometry::Point &p);
  virtual MySQL::Geometry::Rect get_root_bounds() const;

public:
  FigureItem(mdc::Layer *layer, FigureEventHub *hub, BaseFigure *owner);

  std::string get_id() { return _object_id; }
  void set_id(const std::string &id) { _object_id= id; }
  void set_dirty(bool flag= true) { _dirty= flag; }
  bool get_dirty() { return _dirty; }
};


class WBPUBLICBACKEND_PUBLIC_FUNC BaseFigure : public mdc::Box
{
  typedef mdc::Box super;

public:
  typedef std::list<FigureItem*> ItemList;

  // default implementation just sets background color
  virtual void unset_color();
  virtual void set_color(const MySQL::Drawing::Color &color);

  virtual void set_title_font(const mdc::FontSpec &font) {}
  virtual void set_content_font(const mdc::FontSpec &font);
  
  virtual void highlight(const MySQL::Drawing::Color *color= 0);
  virtual void unhighlight();

  virtual void set_allow_manual_resizing(bool flag);

  boost::signals2::signal<void (MySQL::Geometry::Rect)>* signal_interactive_resize() { return &_signal_resize; }

  boost::signals2::signal<void (FigureItem*)>* signal_item_added() { return &_signal_item_added; }

  virtual void toggle(bool flag) {}
  virtual void set_state_drawing(bool flag);
  
  model_ObjectRef represented_object() { return model_ObjectRef(_represented_object); }

  bool in_user_resize() const { return _resizing; }
  
protected:
  BaseFigure(mdc::Layer *layer, FigureEventHub *hub, const model_ObjectRef &object);

  FigureEventHub *_hub;
  model_Object *_represented_object;
  
  boost::signals2::signal<void (MySQL::Geometry::Rect)> _signal_resize;
  boost::signals2::signal<void (FigureItem*)> _signal_item_added;

  MySQL::Geometry::Rect _initial_bounds;
  mdc::FontSpec _content_font;
  bool _manual_resizing;
  bool _resizing;

  void invalidate_min_sizes();
  static void invalidate_min_sizes(mdc::CanvasItem *item);
  
  typedef boost::function<FigureItem* (mdc::Layer*, FigureEventHub*)> CreateItemSlot;
  typedef boost::function<void (FigureItem*)> UpdateItemSlot;

  virtual ItemList::iterator begin_sync(mdc::Box &box, ItemList &list);
  virtual ItemList::iterator sync_next(mdc::Box &box, ItemList &list,
                               ItemList::iterator iter,
                               const std::string &id,
                               cairo_surface_t *icon,
                               const std::string &text,
                               const CreateItemSlot &create_item= CreateItemSlot(),
                               const UpdateItemSlot &update_item= UpdateItemSlot());
  

  virtual void end_sync(mdc::Box &box, ItemList &list, ItemList::iterator iter);

  virtual bool on_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_double_click(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_press(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_button_release(mdc::CanvasItem *target, const MySQL::Geometry::Point &point,
    mdc::MouseButton button, mdc::EventState state);
  virtual bool on_enter(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  virtual bool on_leave(mdc::CanvasItem *target, const MySQL::Geometry::Point &point);
  
  virtual bool on_drag_handle(mdc::ItemHandle *handle, const MySQL::Geometry::Point &pos, bool dragging);
};

  
class WBPUBLICBACKEND_PUBLIC_FUNC ShrinkableBox : public mdc::Box
{
  typedef mdc::Box super;
  
  int _limit_item_count;
  int _hidden_item_count;
  float _visible_part_size;
  bool _manual_resizing;
  
  virtual void render(mdc::CairoCtx *cr);
  virtual void resize_to(const MySQL::Geometry::Size &size);
public:
  ShrinkableBox(mdc::Layer *layer, mdc::Box::Orientation orientation);
  virtual MySQL::Geometry::Size calc_min_size();
  
  void set_item_count_limit(int limit);
  
  void set_allow_manual_resizing(bool flag);
};
  
};

#endif /* _FIGURE_COMMON_H_ */
