
#ifndef _WB_FIND_DIALOG_H_
#define _WB_FIND_DIALOG_H_

#include <string>
#include "wb_backend_public_interface.h"
#include "grts/structs.model.h"
#include "grts/structs.workbench.physical.h"
#include "grts/structs.workbench.logical.h"
#include "grts/structs.workbench.h"
#include "grts/structs.db.h"

#include "grtpp_util.h"
#include "grt/grt_walker.h"

#include "model/wb_model_diagram_form.h"


namespace wb {

  using bec::CatalogIterator;

  class WBContext;

  enum FindResult
  {
    NotFound,
    FoundMatch,
    NoMoreMatches
  };


  class MYSQLWBBACKEND_PUBLIC_FUNC FindDialogBE
  {
  public:
    FindDialogBE(WBContext *wb);
    virtual ~FindDialogBE();

    void set_activate_slot(const boost::function<void (GrtObjectRef, GrtObjectRef, std::string)> &slot);


    void set_text(const std::string &text);
    void set_match_case(bool flag);
    void set_search_in_sql(bool flag);
    void set_search_in_comments(bool flag);
    bool get_search_in_comments() { return _search_in_comments; }
    void set_abort_flag();
    void set_search_diagram_only(bool flag);

    virtual FindResult find_next();
    virtual FindResult find_previous();

  protected:
    grt::ObjectRef get_found_object(std::string &location, std::string &text);

//    void add_custom_search_function(const boost::function<void (FindDialogBE*, model_Model)> &slot);
    void add_match(const GrtObjectRef &object, const std::string &text);
    void add_match(const GrtObjectRef &location, const GrtObjectRef &object, const std::string &text);

    // accept const char* to avoid temporary string creation
    virtual bool match(const char *text);

    template <class T>
      int search_in_name(const grt::Ref<T> &object)
    {
      if (match(object->name().c_str()))
        add_match(object, object->name().c_str());

      return !_abort_flag;
    }

    template <class T>
      int search_in_comment(const grt::Ref<T> &object)
    {
      if (match(object->comment().c_str()))
        add_match(object, object->comment().c_str());

      return !_abort_flag;
    }

    template <class T>
      int search_in_sql(const grt::Ref<T> &object)
    {
      if (match(object->sqlDefinition().c_str()))
        add_match(object, object->sqlDefinition().c_str());

      return !_abort_flag;
    }

  protected:
    struct ResultItem
    {
      GrtObjectRef location;
      GrtObjectRef object;
      std::string text;
    };

    WBContext *_wb;
    gchar *_text, *_lower_text;
    std::vector<ResultItem> _matches;
    long _curmatch;

//    std::list<boost::function<void (FindDialogBE*, model_Model)> > _search_functions;
    bool _match_case;
    bool _search_in_comments;
    bool _search_in_sql;
    bool _changed_param;
    bool _object_activated;
    bool _abort_flag;
    bool _search_diagram_only;


    boost::function<void (GrtObjectRef, GrtObjectRef, std::string)> _activate_result_item;

    //std::stack<GrtObjectRef> *_stack;
    bec::CallStack          *_stack;

    FindResult got_no_results();
    FindResult got_last_match();
    FindResult got_first_match();
    FindResult got_result();

    virtual void do_search();

    template <class T>
    static void do_iterate(T& self, CatalogIterator<T> iter)
    {
      self._object_activated= false;
      self._changed_param= false;
      self._abort_flag= false;
      self._stack= &iter.call_stack;

      self._matches.clear();
            ModelDiagramForm* view_form= dynamic_cast<ModelDiagramForm*>(self._wb->get_active_form());
            if (view_form)
              iter.iterate(self, view_form->get_model_diagram(), true);

      self._curmatch= 0;
      self._stack= 0;
    }

    void activate_found_object();
    bool activate_result_item(const ResultItem  &item);
  };

};

#ifdef _MSC_VER
#pragma make_public(::wb::FindDialogBE)
#endif

#endif
