/* 
 * Copyright (c) 2007, 2010, 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 _SQL_EDITOR_BE_H_
#define _SQL_EDITOR_BE_H_

#include <memory>
#include "base/trackable.h"
#include "wbpublic_public_interface.h"
#include "grt/grt_threaded_task.h"
#include "grtsqlparser/sql_semantic_check.h"
#include "grts/structs.db.mgmt.h"
#include "grts/structs.db.query.h"
#include "grt/grt_manager.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/function.hpp>

/** Base class for SQL Editor Backend classes.
 Subclassed by specific RDBMS support modules.
 */
class WBPUBLICBACKEND_PUBLIC_FUNC Sql_editor : public boost::enable_shared_from_this<Sql_editor>, public base::trackable
{
public:
  typedef boost::shared_ptr<Sql_editor> Ref;
  typedef boost::weak_ptr<Sql_editor> Ptr;
  static Ref create(db_mgmt_RdbmsRef rdbms);
  virtual ~Sql_editor();

  db_query_QueryBufferRef grtobj() { return _grtobj; }
  
  enum KeywordList {General_Keywords, Procedure_Keywords, Client_Keywords, User_Keywords};
  virtual const char *get_keywords(KeywordList list= General_Keywords) const= 0;
  virtual const char *get_function_names() const= 0;

  virtual void setup_scintilla_editor(boost::function<long (int, long, long)> send_editor) = 0;

protected:
  Sql_editor(db_mgmt_RdbmsRef rdbms);

public:
  db_mgmt_RdbmsRef rdbms() { return _rdbms; }
  bec::GRTManager *grtm() { return _grtm; }
protected:
  // ref to the GRT object representing this object
  // it will be used in Db_sql_editor queryBuffer list and in standalone
  // editors for plugin support
  db_query_QueryBufferRef _grtobj;
  
  db_mgmt_RdbmsRef _rdbms;
  bec::GRTManager *_grtm;

public:
  const std::string & eol() const { return _eol; }
  void eol(const std::string &value);
protected:
  std::string _eol;
public:
  boost::signals2::signal<void ()> eol_change_signal;

public:
  int int_option(std::string name);
  std::string string_option(std::string name);
protected:
  grt::DictRef _options;

public:
  const std::string & sql();
  void sql(const std::string &sql);
protected:
  std::string _sql;

public:
  bool is_refresh_enabled() const { return _is_refresh_enabled; }
  void is_refresh_enabled(bool val) { _is_refresh_enabled= val; }
  bool is_sql_check_enabled() const { return _is_sql_check_enabled; }
  void is_sql_check_enabled(bool val) { _is_sql_check_enabled= val; }
protected:
  bool _is_refresh_enabled; // whether FE control is permitted to replace its contents from BE
  bool _is_sql_check_enabled; // whether FE control is permitted to replace its contents from BE

public:
  std::string selected_text();
  void set_selected_text(const std::string &new_text);
  void set_selected_range(int start, int end); // called by UI when selection changes
  bool selected_range(int &start, int &end);
  void set_cursor_pos(int pos);
  int cursor_pos() { return _cursor_pos; }
  void insert_text(const std::string &new_text);
  std::string current_statement();
public:
  boost::signals2::signal<void ()> text_selection_change_signal;
  boost::signals2::signal<void ()> text_change_signal;
  boost::function<int (const std::string&)> replace_selected_text_slot;
  boost::function<void (int, int)> change_selected_range_slot;
  boost::function<void (int)> change_cursor_pos_slot;
  boost::function<int (const std::string&)> insert_text_slot;
  boost::function<std::string ()> current_statement_slot;
protected:
  int _selection_start;
  int _selection_end;
  int _cursor_pos;

public:
  void sql_mode(const std::string &value);

public:
  Sql_semantic_check::Ref sql_checker() { return _sql_checker; }
  typedef Sql_parser_base::Parse_error_cb Sql_parser_err_cb;
  void sql_parser_err_cb(Sql_parser_err_cb cb);
  void check_sql(bool sync);
  bool has_sql_errors() const;
protected:
  grt::StringRef do_check_sql(grt::GRT *grt, Ptr self_ptr);
  int on_sql_error(int lineno, int tok_line_pos, int tok_len, const std::string &msg, int tag);
  int on_sql_check_progress(float progress, const std::string &msg, int tag);
  int on_sql_check_finished();
protected:
  Sql_semantic_check::Ref _sql_checker;
  Sql_parser_err_cb _sql_parser_err_cb;
  GrtThreadedTask::Ref _sql_checker_task;
  GMutex *_sql_checker_mutex;
  int _sql_checker_tag;
protected:
  struct SqlError
  {
    SqlError(int tok_lineno, int tok_line_pos, int tok_len, const std::string &msg, int tag)
      : tok_lineno(tok_lineno), tok_line_pos(tok_line_pos), tok_len(tok_len), msg(msg), tag(tag) {}
    int tok_lineno;
    int tok_line_pos;
    int tok_len;
    std::string msg;
    int tag;
  };
  typedef std::list<SqlError> SqlErrors;
  SqlErrors _sql_errors;
  GMutex *_sql_errors_mutex;
  bool _has_sql_errors;

public:
  boost::signals2::signal<void ()> sql_check_finish_signal;

public:
  typedef Sql_parser_base::Report_sql_statement_border Report_sql_statement_border;
  Report_sql_statement_border report_sql_statement_border;
private:
  int on_report_sql_statement_border(int begin_lineno, int begin_line_pos, int end_lineno, int end_line_pos, int tag);
public:
  struct SqlStatementBorder
  {
    SqlStatementBorder(int tag, int begin_lineno, int begin_line_pos, int end_lineno, int end_line_pos)
      : tag(tag), begin_lineno(begin_lineno), begin_line_pos(begin_line_pos), end_lineno(end_lineno), end_line_pos(end_line_pos) {}
    int tag; // version (incremented by each parsing) used to filter outdated data
    int begin_lineno;
    int begin_line_pos;
    int end_lineno;
    int end_line_pos;
  };
  SqlStatementBorder get_sql_statement_border_by_line_pos(int lineno, int line_pos);
private:
  typedef std::list<SqlStatementBorder> SqlStatementBorders;
  SqlStatementBorders _sql_statement_borders;
  SqlStatementBorders _sql_statement_borders_cache;
  GMutex *_sql_statement_borders_mutex;
  GMutex *_sql_statement_borders_cache_mutex;
  
public:
  bec::MenuItemList get_context_menu();
  void activate_context_menu_item(const std::string &name);
    
public:
  void sql_check_progress_msg_throttle(time_t val);
private:
  void request_sql_check_results_refresh();
private:
  time_t _last_sql_check_progress_msg_timestamp;
  time_t _sql_check_progress_msg_throttle;
};


#ifdef _WIN32 
#pragma make_public(Sql_editor) 
#endif 
 

#endif /* _SQL_EDITOR_BE_H_ */
