/* 
 * © 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.
 */
/**
 * Implementation of the GRT treeview wrapper for the mforms library. We use a third-party tree view control
 * here (TreeViewAdv) which supports columns.
 */

#include "stdafx.h"
#include "wf_grttreeview.h"

using namespace MySQL;
using namespace MySQL::Forms;
using namespace MySQL::Grt;

//--------------------------------------------------------------------------------------------------

/**
 * Triggered when a node icon is double clicked. Used to trigger GRT row activation (which in turn
 * triggers other actions).
 *
 * @param
 * @return
 */
void SwitchNodeIcon::MouseDoubleClick(TreeNodeAdvMouseEventArgs^ args)
{
  TreeViewAdv^ tree= args->Control->Parent;
  SimpleGrtTreeModel^ model= (SimpleGrtTreeModel^) tree->Model;
  ::mforms::GRTTreeView* be_tree= ViewImpl::get_backend_control<::mforms::GRTTreeView>(tree);
  if (be_tree != NULL)
  {
    ::bec::NodeId* nodeId= ((GrtTreeNode^) args->Node->Tag)->NodeId->get_unmanaged_object();
    be_tree->row_activate_callback(*nodeId, model->GetColumnIndex(args->Control));
    args->Handled= true; // Prevent this node from collapsing/expanding.
  }
}

//----------------- GRTTreeViewImpl static interface functions ----------------------------------------

bool GRTTreeViewImpl::create(::mforms::GRTTreeView *self, bool flag)
{
  GRTTreeViewImpl ^treeview= gcnew GRTTreeViewImpl(self);

  if (treeview != nullptr)
  {
    TreeViewAdv^ t= ViewImpl::create<TreeViewAdv>(self, treeview);

    //t->UseColumns= options & ::mforms::TreeUseColumns ? true : false;
    //t->ShowLines= options & ::mforms::TreeShowLines ? true : false;
    //t->ShowPlusMinus= options & ::mforms::TreeShowPlusMinus ? true : false;
    return true;
  }
  return false;
}

//--------------------------------------------------------------------------------------------------

void GRTTreeViewImpl::set_model(::mforms::GRTTreeView *self, bec::TreeModel *model)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
  {
    treeview->_tree_model= gcnew MySQL::Grt::TreeModel(model);
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();
    treeview->_model= gcnew SimpleGrtTreeModel(t, treeview->_tree_model);

    // Before setting the new model in the tree control see if we have any columns cached.
    // If so then they were created before the model was set and could not yet be finished.
    // Do the final step now.
    for each (ColumnEntry^ entry in treeview->_columns)
    {
      if (entry->isIcon)
        treeview->_model->AddColumn((NodeIcon^) (entry->nodeControl), entry->column);
      else
        treeview->_model->AddColumn(entry->nodeControl, entry->column, entry->editable);
    }

    // Finally set the model.
    t->Model= treeview->_model;
  }
}

//--------------------------------------------------------------------------------------------------

int GRTTreeViewImpl::add_column(::mforms::GRTTreeView *self, ::mforms::GRTTreeColumnType type, int model_column, 
                                const string &name)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
    return treeview->add_column(type, model_column, CppStringToNative(name), false);
  return -1;
}

//--------------------------------------------------------------------------------------------------

int GRTTreeViewImpl::add_column_editable(::mforms::GRTTreeView *self, ::mforms::GRTTreeColumnType type, int model_column, 
                                const string &name)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
    return treeview->add_column(type, model_column, CppStringToNative(name), true);
  return -1;
}

//--------------------------------------------------------------------------------------------------

void GRTTreeViewImpl::refresh(mforms::GRTTreeView* self, const bec::NodeId &node)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
  {
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();
    for each (TreeNodeAdv^ current_node in t->AllNodes)
      if ((*((GrtTreeNode^) current_node->Tag)->NodeId->get_unmanaged_object()) == node)
      {
        treeview->_model->RefreshModel(t->GetPath(current_node));
        return;
      }

    treeview->_model->RefreshModel();
  }
}

//--------------------------------------------------------------------------------------------------

void GRTTreeViewImpl::set_column_width(mforms::GRTTreeView *self, int column, int width)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
  {
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();
    t->Columns[column]->Width= width;
  }
}

//--------------------------------------------------------------------------------------------------

int GRTTreeViewImpl::get_selection(mforms::GRTTreeView *self, std::vector<bec::NodeId> &nodes)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  nodes.clear();
  if (treeview != nullptr)
  {
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();

    if (t->SelectedNodes != nullptr)
    {
      for each (TreeNodeAdv^ node in t->SelectedNodes)
        nodes.push_back(*((GrtTreeNode^) node->Tag)->NodeId->get_unmanaged_object());
      return nodes.size();
    }
  }
  return 0;
}

//--------------------------------------------------------------------------------------------------

bool GRTTreeViewImpl::get_selected_node(::mforms::GRTTreeView *self, bec::NodeId &node)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
  {
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();

    if (t->SelectedNode != nullptr)
      node= *((GrtTreeNode^) t->SelectedNode->Tag)->NodeId->get_unmanaged_object();
  }
  return false;
}

//--------------------------------------------------------------------------------------------------

void GRTTreeViewImpl::set_allow_multi_selection(::mforms::GRTTreeView *self, bool flag)
{
  GRTTreeViewImpl^ treeview= (GRTTreeViewImpl^)ObjectImpl::FromUnmanaged(self);
  if (treeview != nullptr)
  {
    TreeViewAdv^ t= treeview->get_control<TreeViewAdv>();
    t->SelectionMode= flag ? TreeSelectionMode::Multi : TreeSelectionMode::Single;
  }
}

//----------------- Actual implementation ----------------------------------------------------------

GRTTreeViewImpl::GRTTreeViewImpl(::mforms::GRTTreeView *self)
: ViewImpl(self)
{
  _model= nullptr;
}

//--------------------------------------------------------------------------------------------------

/**
 * This method adds a new column control to either the tree or the internal cache.
 *
 * @param control The node control used for this column.
 * @param column The column index for this column.
 * @param editable Is the column editable?
 * @param isIcon Is this an icon control? (needs a slightly different handling)
 */
void GRTTreeViewImpl::add_node_control(BindableControl^ control, int column, bool editable, bool isIcon)
{
  if (_model == nullptr)
    _columns.Add(gcnew ColumnEntry(control, column, editable, isIcon));
  else
    if (isIcon)
      _model->AddColumn((NodeIcon^) control, column);
    else
      _model->AddColumn(control, column, editable);
}

//--------------------------------------------------------------------------------------------------

int GRTTreeViewImpl::add_column(::mforms::GRTTreeColumnType type, int model_column, String ^name, bool editable)
{
  TreeViewAdv^ treeview= get_control<TreeViewAdv>();
  
  TreeColumn^ column= gcnew TreeColumn(name, 150);
  treeview->Columns->Add(column);
  treeview->UseColumns= true;

  BindableControl^ control;
  bool isIcon= false;
  switch (type)
  {
  case ::mforms::StringGRTColumnType:
    {
      control= gcnew NodeTextBox();
      control->LeftMargin= 3;
      break;
    }
  case ::mforms::IconStringGRTColumnType:
    {
      // This type need two node controls (icon and text).
      control= gcnew NodeIcon();
      control->ParentColumn= column;
      treeview->NodeControls->Add(control);
      add_node_control(control, model_column, editable, true);

      control= gcnew NodeTextBox();
      control->LeftMargin= 3;
      break;
    }
  case ::mforms::IntegerGRTColumnType:
    {
      control= gcnew NodeTextBox();
      control->LeftMargin= 3;
      break;
    }
  case ::mforms::CheckGRTColumnType:
    {
      control= gcnew NodeCheckBox();
      control->LeftMargin= 3;
    }
    break;

  default: // ::mforms::IconGRTColumnType:
    {
      control= gcnew SwitchNodeIcon();
      isIcon= true;
      break;
    }
  };

  control->ParentColumn= column;
  treeview->NodeControls->Add(control);

  add_node_control(control, model_column, editable, isIcon);

  return column->Index;
}

//--------------------------------------------------------------------------------------------------

