#ifndef __TREE_MODEL_H__
#define __TREE_MODEL_H__

#pragma make_public(::bec::ListModel)

#include "GrtTemplates.h"
#include "UIForm.h"
#include "IconManager.h"

namespace MySQL {
  namespace Grt {

    // -------------------------------------------------------------------------------------------------------------
    public ref class NodeId
    {
    protected:
      ::bec::NodeId *inner;

    public:
      NodeId(const ::bec::NodeId *inn)
        : inner(new ::bec::NodeId(*inn))
      {}

      NodeId() 
        : inner(new ::bec::NodeId()) 
      {}

      NodeId(int index)
        : inner(new ::bec::NodeId(index))
      {}

      NodeId(String ^str)
        : inner(new ::bec::NodeId(NativeToCppString(str)))
      {}

      ~NodeId() 
      { delete inner; }

      ::bec::NodeId *get_unmanaged_object()
      { return inner; }

      bool operator == (NodeId^ node)
      { return inner->operator == (*node->inner); }

      bool equals(NodeId^ node)
      { return inner->operator == (*node->inner); }

      int operator[] (int i)
      { return inner->operator[](i); }

      int get_by_index (int i)
      { return inner->operator[](i); }

      int depth()
      { return inner->depth(); }

      int back()
      { return inner->back(); }

      NodeId^ append(int i)
      { inner->append(i); return this; }

      bool is_valid()
      { return inner->is_valid(); }

      String^ repr()
      { return CppStringToNative(inner->repr()); }
    };

    // -------------------------------------------------------------------------------------------------------------
    public ref class ListModel
    {
    protected:
      ::bec::ListModel *inner;

    public:
     
      ListModel(::bec::ListModel *inn)
        : inner(inn)
      {}

      virtual ~ListModel() 
      {}

      bool is_valid()
      { return inner != NULL; }

      virtual int count()
      { return inner->count(); }

      virtual NodeId^ get_node(int index)
      { return gcnew NodeId(&inner->get_node(index)); }

      virtual bool get_field(NodeId^ node, int column, [Out] String^ %value)
      {
        std::string str;
        bool retval= inner->get_field(*node->get_unmanaged_object(), column, str);
        value= CppStringToNative(str);
        return retval;
      }

      virtual bool get_field(NodeId^ node, int column, [Out] int %value)      
      {
        int v;
        bool retval= inner->get_field(*node->get_unmanaged_object(), column, v);
        value= v;
        return retval;
      }

      virtual bool get_field(NodeId^ node, int column, [Out] double %value)
      {
        double v;
        bool retval= inner->get_field(*node->get_unmanaged_object(), column, v);
        value= v;
        return retval;
      }

      virtual String^ get_field_description(NodeId^ node, int column)
      { return CppStringToNative(inner->get_field_description(*node->get_unmanaged_object(), column)); }

      virtual IconId get_field_icon(NodeId^ node, int column, IconSize size)
      {
        return inner->get_field_icon(*node->get_unmanaged_object(), column, (bec::IconSize) size);
      }

      virtual GrtValue^ get_grt_value(NodeId^ node, int column)
      { return gcnew GrtValue(inner->get_grt_value(*node->get_unmanaged_object(), column)); }

      virtual void refresh()
      { inner->refresh(); }

      virtual GrtValueType^ get_field_type(NodeId^ node, int column)
      { return static_cast<GrtValueType>(inner->get_field_type(*node->get_unmanaged_object(), column)); }

      // for editable lists only
      virtual bool set_field(NodeId^ node, int column, String^ value)
      { return inner->set_field(*node->get_unmanaged_object(), column, NativeToCppString(value)); }

      virtual bool set_field(NodeId^ node, int column, double value)
      { return inner->set_field(*node->get_unmanaged_object(), column, value); }

      virtual bool set_field(NodeId^ node, int column, int value)
      { return inner->set_field(*node->get_unmanaged_object(), column, value); }

      virtual bool set_convert_field(NodeId^ node, int column, String^ value)
      {
        return inner->set_convert_field(*node->get_unmanaged_object(), column, NativeToCppString(value));
      }

      virtual bool activate_node(NodeId^ node)
      {
        return inner->activate_node(*node->get_unmanaged_object());
      }

      std::vector<bec::NodeId> convert_node_list(List<NodeId^> ^nodes)
      {
        return ObjectListToCppVector<NodeId, bec::NodeId>(nodes);
      }

      virtual List<MySQL::Grt::MenuItem^> ^get_popup_items_for_nodes(List<NodeId^> ^nodes)
      {
        bec::MenuItemList item_list= inner->get_popup_items_for_nodes(convert_node_list(nodes));
        List<MySQL::Grt::MenuItem^> ^items= gcnew List<MySQL::Grt::MenuItem^>();

        for (bec::MenuItemList::const_iterator iter= item_list.begin(); iter != item_list.end(); ++iter)
          items->Add(gcnew MySQL::Grt::MenuItem(*iter));

        return items;
      }

      virtual bool activate_popup_item_for_nodes(String ^name, List<NodeId^> ^nodes)
      {
        return inner->activate_popup_item_for_nodes(NativeToCppString(name), convert_node_list(nodes));
      }

      virtual bool delete_node(NodeId^ node) 
      {
        return inner->delete_node(*node->get_unmanaged_object());
      }

      void reorder(NodeId^ node, int index)
      {
        inner->reorder(*node->get_unmanaged_object(), index);
      }

      void reorder_up(NodeId^ node)
      {
        inner->reorder_up(*node->get_unmanaged_object());
      }

      void reorder_down(NodeId^ node)
      {
        inner->reorder_down(*node->get_unmanaged_object());
      }

      bool is_editable(NodeId^ node)
      {
        return inner->is_editable(*node->get_unmanaged_object());
      }

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

    // -------------------------------------------------------------------------------------------------------------
    public ref class TreeModel : public ListModel
    {
    public:
      TreeModel(::bec::TreeModel *inn)
        : ListModel(inn)
      {}

      inline ::bec::TreeModel *get_unmanaged_object()
      { return static_cast<::bec::TreeModel *>(inner); }

      virtual NodeId^ get_root()
      { return gcnew NodeId(&get_unmanaged_object()->get_root()); }

      virtual int get_node_depth(NodeId^ node)
      { return get_unmanaged_object()->get_node_depth(*node->get_unmanaged_object()); }

      virtual NodeId^ get_parent(NodeId^ node)
      { return gcnew NodeId(&get_unmanaged_object()->get_parent(*node->get_unmanaged_object())); }

      virtual int count_children(NodeId^ parent)
      { return get_unmanaged_object()->count_children(*parent->get_unmanaged_object()); }

      virtual NodeId^ get_child(NodeId^ parent, int index)
      { return gcnew NodeId(&get_unmanaged_object()->get_child(*parent->get_unmanaged_object(), index)); }

      virtual bool expand_node(NodeId^ node)
      { return get_unmanaged_object()->expand_node(*node->get_unmanaged_object()); }

      virtual void collapse_node(NodeId^ node)
      { return get_unmanaged_object()->collapse_node(*node->get_unmanaged_object()); }

      virtual bool is_expandable(NodeId^ node)
      { return get_unmanaged_object()->is_expandable(*node->get_unmanaged_object()); }
    };

    // -------------------------------------------------------------------------------------------------------------
    public ref class GridModel : public ListModel
    {
    public:
      enum class ColumnType
      {
        StringType = ::bec::GridModel::StringType,
        NumericType = ::bec::GridModel::NumericType,
        DatetimeType = ::bec::GridModel::DatetimeType,
        BlobType = ::bec::GridModel::BlobType
      };

      GridModel(::bec::GridModel *inn)
        : ListModel(inn)
      {}

      inline ::bec::GridModel *get_unmanaged_object()
      { return static_cast<::bec::GridModel *>(inner); }

        
      virtual int get_column_count() 
      { return get_unmanaged_object()->get_column_count(); }

      virtual String^ get_column_caption(int column)
      { return CppStringToNative(get_unmanaged_object()->get_column_caption(column)); }

      virtual ColumnType get_column_type(int column) 
      { return (ColumnType)get_unmanaged_object()->get_column_type(column); }
    };

  } // namespace Grt
} // namespace MySQL

#endif // __TREE_MODEL_H__
