
#ifndef _WB_MODEL_DIAGRAM_FORM_H_
#define _WB_MODEL_DIAGRAM_FORM_H_

#include "wb_context.h"



namespace wb {
  class Floater;  
  
  enum EditFinishReason
  {
    EditCancelled,
    EditReturnPressed,
    EditTabPressed,
    EditShiftTabPressed
  };

  
  class ModelDiagramForm;
  class PhysicalModelDiagramFeatures;

  class InlineEditContext
  {
    sigc::signal<void, std::string, EditFinishReason> _signal_edit_finished;

  public:
    virtual ~InlineEditContext() {}

    virtual void begin_editing(int x, int y, int width, int height, const std::string &text)= 0;
    virtual void end_editing()= 0;

    virtual void set_font_size(float size)= 0;
    virtual void set_multiline(bool flag)= 0;

    sigc::signal<void, std::string, EditFinishReason> signal_edit_finished() { return _signal_edit_finished; }
  };


  class MYSQLWBBACKEND_PUBLIC_FUNC ModelDiagramForm : public bec::UIForm
  {
  public:
    ModelDiagramForm(WBComponent *owner, const model_DiagramRef &view);
    virtual ~ModelDiagramForm();

    void attach_canvas_view(mdc::CanvasView *cview);

    virtual bool is_main_form() { return true; }
    virtual std::string get_form_context_name() const { return WB_CONTEXT_MODEL; }

    mdc::CanvasView *get_view() { return _view; }
    model_DiagramRef &get_model_diagram() { return _model_diagram; }

    grt::DictRef get_model_options() { return _model_diagram->owner()->options(); }
    grt::DictRef get_diagram_options() { return _model_diagram->options(); }

    void set_closed(bool flag);
    bool is_closed();
    
    mdc::CanvasItem *get_leaf_item_at(const mdc::Point &pos);
    
    virtual grt::UndoManager *get_undo_manager();

    bec::Clipboard *get_clipboard();

    virtual std::string get_title() { return _model_diagram->name().c_str(); }
    
    virtual bool can_copy();
    virtual bool can_paste();
    virtual bool can_delete();
    virtual bool can_select_all();

    virtual void cut();
    virtual void copy();
    virtual void paste();
    virtual void delete_selection();
    virtual void select_all();

    int delete_selection(bool noquestions);

    virtual std::string get_edit_target_name();
    
    std::string get_diagram_info_text();

    grt::ListRef<model_Object> get_selection();
    grt::ListRef<model_Object> get_copiable_selection();
    bool has_selection();

    double get_zoom();
    void set_zoom(double zoom);
    void zoom_in();
    void zoom_out();

    void set_button_callback(const sigc::slot<bool, ModelDiagramForm*, mdc::MouseButton, bool, mdc::Point, mdc::EventState> &cb);
    void set_motion_callback(const sigc::slot<bool, ModelDiagramForm*, mdc::Point, mdc::EventState> &cb);
    void set_reset_tool_callback(const sigc::slot<void, ModelDiagramForm*> &cb);

    std::string get_tool() { return _tool; }
    void set_tool(const std::string &tool);
    void reset_tool(bool notify);
    void set_tool_argument(const std::string &option, const std::string &value);
    std::string get_tool_argument(const std::string &option);

    bool is_visible(const model_ObjectRef &object, bool partially);
    void focus_and_make_visible(const model_ObjectRef &object, bool select);
    
    bool search_and_focus_object(const std::string &text);

    void set_cursor(const std::string &cursor);
    inline const std::string &get_cursor() { return _cursor; }

    // events
    void handle_mouse_move(int x, int y, mdc::EventState state);
    void handle_mouse_button(mdc::MouseButton button, bool press, int x, int y, mdc::EventState state);
    void handle_key(const mdc::KeyInfo &key, bool press, mdc::EventState state);

    bool current_mouse_position(int &x, int &y);
    bool current_mouse_position(mdc::Point &pos);

    // drag&drop
    std::vector<std::string> get_accepted_drop_types();
    
    bool accepts_drop(int x, int y, const std::string &type, const std::list<GrtObjectRef> &objects);
    bool accepts_drop(int x, int y, const std::string &type, const std::string &text);

    bool perform_drop(int x, int y, const std::string &type, const std::list<GrtObjectRef> &objects);
    bool perform_drop(int x, int y, const std::string &type, const std::string &text);


    model_LayerRef get_layer_at(const mdc::Point &pos, mdc::Point &offset);
    model_LayerRef get_layer_bounding(const mdc::Rect &rect, mdc::Point &offset);
    model_ObjectRef get_object_at(const mdc::Point &pos);


    mdc::Layer *get_floater_layer();
    void add_floater(Floater *floater);


    void enable_panning(bool flag);

    sigc::signal<void, std::string> signal_tool_argument_changed() { return _tool_argument_changed; }

    WBComponent *get_owner() { return _owner; }


    // inline editing
    void begin_editing(const mdc::Rect &rect, const std::string &text, float text_size, bool multiline);
    void stop_editing();
    sigc::signal<void,std::string,EditFinishReason> signal_editing_done() { return _signal_editing_done; }

    void set_inline_editor_context(InlineEditContext *context);

  protected:
    struct OldPosition
    {
      mdc::Point pos;
      std::string layer_id;
    };

    mdc::CanvasView *_view;
    mdc::Layer *_main_layer;
    mdc::Layer *_floater_layer;
    mdc::Layer *_badge_layer;
    WBComponent *_owner;
    model_DiagramRef _model_diagram;
    int _current_mouse_x;
    int _current_mouse_y;
    std::string _tool;
    std::string _cursor;
    std::map<std::string, std::string> _tool_args;
    std::vector<WBShortcut> _shortcuts;
    
    PhysicalModelDiagramFeatures *_features;

    std::map<grt::internal::Value*, OldPosition> _old_positions;
    InlineEditContext *_inline_edit_context;
    sigc::signal<void,std::string,EditFinishReason> _signal_editing_done;

    double _paste_offset;

    sigc::signal<void, std::string> _tool_argument_changed;

    sigc::slot<bool, ModelDiagramForm*, mdc::MouseButton, bool, mdc::Point, mdc::EventState> _handle_button;
    sigc::slot<bool, ModelDiagramForm*, mdc::Point, mdc::EventState> _handle_motion;
    sigc::slot<void, ModelDiagramForm*> _reset_tool;


    bool _drag_panning;
    bool _space_panning;

    // saved state for tmp panning
    std::string _old_tool;
    std::string _old_cursor;
    sigc::slot<void, ModelDiagramForm*> _old_reset_tool;
    sigc::slot<bool, ModelDiagramForm*, mdc::MouseButton, bool, mdc::Point, mdc::EventState> _old_handle_button;
    sigc::slot<bool, ModelDiagramForm*, mdc::Point, mdc::EventState> _old_handle_motion;

    void clipboard_changed();

    bool relocate_figures();

    void begin_selection_drag();
    void end_selection_drag();
    
    
    
    
    //void hover_in_figure(mdc::CanvasItem *item, mdc::Point pos);
    //void hover_out_figure(mdc::CanvasItem *item);
  };

};


#endif
