/* 
 * © 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifndef _EDITOR_TABLE_H_
#define _EDITOR_TABLE_H_

#include "grtdb/editor_dbobject.h"
#include "grtdb/editor_table_inserts.h"
#include "grt/tree_model.h"

#include "grtdb/charset_list.h"

#include "grts/structs.db.mgmt.h"

#include "wbpublic_public_interface.h"

#define TableEditorBE_VERSION 2


namespace bec {

  class TableEditorBE;
  class IndexListBE;
  class FKConstraintListBE;

  // ColumnNamesSet sets alias for type which is used to return a set of all column
  // names from all tables in the schema. This type is used by TableColumnsListBE
  typedef std::set<std::string>  ColumnNamesSet;

  class WBPUBLICBACKEND_PUBLIC_FUNC TableColumnsListBE : public ListModel
  {
  public:
    enum ColumnListColumns {
      Name,
        Type,
        IsPK,
        IsNotNull,
        //IsUnique,
        IsBinary,
        IsUnsigned,
        IsZerofill,
        Flags,
        Default,
        CharsetCollation,
        Charset,
        Collation,
        Comment,
        HasCharset,
      
        LastColumn
    };
    
    TableColumnsListBE(TableEditorBE *owner);
    
    bool get_row(const NodeId &node,
                 std::string &name,
                 std::string &type,
                 bool &ispk,
                 bool &notnull,
                 //bool &isunique,
                 bool &isbinary,
                 bool &isunsigned,
                 bool &iszerofill,
                 std::string &flags,
                 std::string &defvalue,
                 std::string &charset,
                 std::string &collation,
                 std::string &comment
                 );

    virtual IconId get_field_icon(const NodeId &node, int column, IconSize size);

    virtual void refresh();
    virtual int count();
    int real_count();

    bool set_column_type(const NodeId &node, const GrtObjectRef &type);

    bool set_column_type_from_string(db_ColumnRef &column, const std::string &type);
    
    virtual bool set_field(const NodeId &node, int column, const std::string &value);
    virtual bool set_field(const NodeId &node, int column, int value);

    virtual void reorder(const NodeId &node, int nindex);

    std::vector<std::string> get_datatype_flags(const ::bec::NodeId &node, bool all=false);
    bool set_column_flag(const ::bec::NodeId &node, const std::string& flag_name, int is_set);
    int get_column_flag(const ::bec::NodeId &node, const std::string& flag_name);

    virtual std::string quote_value_if_needed(const db_ColumnRef &column, const std::string &value);
    virtual MenuItemList get_popup_items_for_nodes(const std::vector<NodeId> &nodes);
    virtual bool activate_popup_item_for_nodes(const std::string &name, const std::vector<NodeId> &nodes);

    virtual bool can_delete_node(const NodeId &node);
    virtual bool delete_node(const NodeId &node);
    
    virtual std::vector<std::string> get_datatype_names();
    
    ColumnNamesSet get_column_names_completion_list() const;

  protected:
    TableEditorBE *_owner;
    int _editing_placeholder_row;
        
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, int column, grt::ValueRef &value);
  };
  
  
  
  class WBPUBLICBACKEND_PUBLIC_FUNC IndexColumnsListBE : public ListModel
  {
  public:
    enum IndexColumnsListColumns {
        Name,
        Descending,
        Length,
        OrderIndex
    };
    
    IndexColumnsListBE(IndexListBE *owner);
    
    virtual void refresh();
    virtual int count();

    void set_column_enabled(const NodeId &node, bool flag);
    bool get_column_enabled(const NodeId &node);

    virtual bool set_field(const NodeId &node, int column, int value);
    virtual bool set_field(const NodeId &node, int column, const std::string &value);

    int get_max_order_index();

  protected:
    IndexListBE *_owner;
    
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, int column, grt::ValueRef &value);
    
    db_IndexColumnRef get_index_column(const db_ColumnRef &column);
    int get_index_column_index(const db_ColumnRef &column);
    void set_index_column_order(const db_IndexColumnRef &column, int order);
  };
  
  
  
  class WBPUBLICBACKEND_PUBLIC_FUNC IndexListBE : public ListModel
  {
    friend class IndexColumnsListBE;
    friend class TableEditorBE;
    
  public:
    enum IndexListColumns {
      Name,
        Type,
        Comment,
        LastColumn
    };
    
    IndexListBE(TableEditorBE *owner);

    virtual void refresh();
    virtual int count();
    int real_count();
    
    // for editable lists only
    virtual bool set_field(const NodeId &node, int column, const std::string &value);
    
    IndexColumnsListBE *get_columns() { return &_column_list; }
    
    
    db_IndexRef get_selected_index();
    void select_index(const NodeId &node);

    bool index_editable(const db_IndexRef &index);

    TableEditorBE *get_owner() { return _owner; }
    
    virtual MenuItemList get_popup_items_for_nodes(const std::vector<NodeId> &nodes);
    virtual bool activate_popup_item_for_nodes(const std::string &name, const std::vector<NodeId> &nodes);
    
    virtual bool can_delete_node(const NodeId &node);
    virtual bool delete_node(const NodeId &node);

  protected:
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, int column, grt::ValueRef &value);

    NodeId add_column(const db_ColumnRef &column, const db_IndexRef &index= db_IndexRef());
    void remove_column(const NodeId &node);

  protected:
    IndexColumnsListBE _column_list;
    TableEditorBE *_owner;
    NodeId _selected;
  };
  
  
  
  class WBPUBLICBACKEND_PUBLIC_FUNC FKConstraintColumnsListBE : public ListModel
  {
  public:
    enum FKConstraintColumnsListColumns {
      Enabled,
      Column,
      RefColumn
    };
    
    FKConstraintColumnsListBE(FKConstraintListBE *owner);
    
    virtual void refresh();
    virtual int count();

    std::vector<std::string> get_ref_columns_list(const NodeId &node);

    // for editable lists only
    virtual bool set_field(const NodeId &node, int column, const std::string &value);
    virtual bool set_field(const NodeId &node, int column, int value);

    bool set_column_is_fk(const NodeId &node, bool flag);
    int get_fk_column_index(const NodeId &node);
    bool get_column_is_fk(const NodeId &node);
    
    FKConstraintListBE *get_owner() { return _owner; }
    
  protected:
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, int column, grt::ValueRef &value);
    
    bool set_fk_column_pair(const db_ColumnRef &column, const db_ColumnRef &refcolumn); 
    
    // temporary list of referenced columns for each FK column
    // if id is in the map, then it's enabled, if column is nil, it's unset
    // only valid entries will be commited to actual table
    std::map<std::string, db_ColumnRef> _referenced_columns; 
    
    FKConstraintListBE *_owner;
  };
  
  
  
  class WBPUBLICBACKEND_PUBLIC_FUNC FKConstraintListBE : public ListModel
  {
    friend class FKConstraintColumnsListBE;
    
  public:
    enum FKConstraintListColumns {
      Name,
        OnDelete,
        OnUpdate,
        RefTable,
        Comment
    };
    FKConstraintListBE(TableEditorBE *owner);
    
    NodeId add_column(const db_ColumnRef &column, const db_ColumnRef &refcolumn, 
      const db_ForeignKeyRef &fk= db_ForeignKeyRef());

    virtual void remove_column(const NodeId &node);

    virtual void refresh();
    virtual int count();
    int real_count();

    // for editable lists only
    virtual bool set_field(const NodeId &node, int column, const std::string &value);
    virtual bool set_field(const NodeId &node, int column, int value);
    
    void select_fk(const NodeId &node);
    db_ForeignKeyRef get_selected_fk();
    
    TableEditorBE *get_owner() { return _owner; }
    
    FKConstraintColumnsListBE *get_columns() { return &_column_list; }

    virtual bool can_delete_node(const NodeId &node);
    virtual bool delete_node(const NodeId &node);

    virtual MenuItemList get_popup_items_for_nodes(const std::vector<NodeId> &nodes);
    virtual bool activate_popup_item_for_nodes(const std::string &name, const std::vector<NodeId>& nodes);
  protected:
    // for internal use only
    virtual bool get_field_grt(const NodeId &node, int column, grt::ValueRef &value);
    
  protected:
    FKConstraintColumnsListBE _column_list;
    TableEditorBE *_owner;
    NodeId _selected_fk;
    int    _editing_placeholder_row;
  };
  
  
  class WBPUBLICBACKEND_PUBLIC_FUNC TableEditorBE : public DBObjectEditorBE
  {
  public:
    enum PartialRefreshes
    {
      RefreshColumnList,
      RefreshColumnCollation
    };

    virtual db_DatabaseObjectRef get_dbobject() { return get_table(); }
    virtual db_TableRef get_table()= 0;

    virtual TableColumnsListBE *get_columns()= 0;
    virtual IndexListBE *get_indexes()= 0;
    FKConstraintListBE *get_fks() { return &_fk_list; }
    TableInsertsGridBE *get_inserts_grid() { return &_inserts_grid; }

    virtual void set_name(const std::string &name);

    // table options
    virtual void set_table_option_by_name(const std::string& name, const std::string& value) = 0;
    virtual std::string get_table_option_by_name(const std::string& name) = 0;

    // column editing
    virtual NodeId add_column(const std::string &name);
    virtual void remove_column(const NodeId &column);
    void rename_column(const db_ColumnRef &column, const std::string &name);

    db_ColumnRef get_column_with_name(const std::string &name);

    // fk editing
    virtual NodeId add_fk(const std::string &name);
    virtual bool remove_fk(const NodeId &fk);
    virtual NodeId add_fk_with_columns(const std::vector<NodeId> &columns);  

    // index editing
    virtual NodeId add_index(const std::string &name);
    virtual bool remove_index(const NodeId &index);

    virtual NodeId add_index_with_columns(const std::vector<NodeId> &columns);

    // helper utils for columns
    virtual bool parse_column_type(const std::string &str, db_ColumnRef &column);
    virtual std::string format_column_type(db_ColumnRef &column);

    virtual std::vector<std::string> get_index_types()= 0;

    virtual void set_triggers_sql(const std::string &sql);
    grt::ValueRef parse_triggers_sql(grt::GRT*, grt::StringRef sql);

    virtual Sql_editor * get_sql_editor();

    bool update_inserts_grid();
    void update_from_inserts_grid();
    bool set_inserts(const std::string &text);
    std::string get_inserts();

  protected:
    db_TableRef _table;
    FKConstraintListBE _fk_list;
    TableInsertsGridBE _inserts_grid;

    TableEditorBE(GRTManager *grtm,
                  const db_TableRef &table,
                  const db_mgmt_RdbmsRef &rdbms);
    
    void undo_called(grt::UndoAction *action, grt::UndoAction *expected);
  };

};


#ifdef _WIN32
#pragma make_public(::bec::TableColumnsListBE)
#pragma make_public(::bec::IndexListBE)
#pragma make_public(::bec::TableEditorBE)
#endif

#endif /* _EDITOR_TABLE_H_ */
