/* 
 * 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
 */

#include "stdafx.h"

#include "wb_layer_tree.h"
#include "wb_context.h"
#include "model/wb_model_diagram_form.h"
#include "grts/structs.model.h"
#include "grts/structs.workbench.physical.h"
#include "grtpp_undo_manager.h"
#include "base/string_utilities.h"

#include <set>

using namespace wb;
using namespace bec;
using namespace base;

void LayerTreeBE::rescan_node(const NodeId &node_id, Node *node, const std::string &path, const grt::ObjectRef &value)
{
  node->reset_children();

  model_LayerRef layer;
  bool is_root= false;

  if (node_id.depth() == 1)
  {
    model_DiagramRef view(model_DiagramRef::cast_from(value));

    layer= view->rootLayer();
    is_root= true;

    for (size_t c= view->layers().count(), i= 0; i < c; i++)
    {
      model_LayerRef subLayer(view->layers().get(i));
      char buffer[30];
#ifdef __GNUC__
      snprintf(buffer, sizeof(buffer), "layers/%zi", i);
#else
      snprintf(buffer, sizeof(buffer), "layers/%li", i);
#endif
      FigureNode *child= new FigureNode();
      child->path= buffer;
      child->name= subLayer->name();
      child->color= subLayer->color();
      child->expandable= true;
      child->id= subLayer.id();
      child->selected= _selected.find(child->id) != _selected.end() ? 2 : 0;
      child->is_layer= 1;
      child->small_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(subLayer), Icon16);
      child->large_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(subLayer), Icon48);

      node->subnodes.push_back(child);
    }
    std::sort(node->subnodes.begin(), node->subnodes.end(), sortnode());

    // create mapping of figures to connections
    _figure_connections.clear();
    grt::ListRef<model_Connection> connections(view->connections());
    for (size_t c= connections.count(), i= 0; i < c; i++)
    {
      if (connections[i]->startFigure().is_valid())
        _figure_connections.insert(std::pair<std::string, size_t>(connections[i]->startFigure().id(), i));
    }

    // fall through to fill root layer figures
  }
  else if (value.is_instance(model_Layer::static_class_name()))
    layer= model_LayerRef::cast_from(value);
  else if (value.is_instance(model_Figure::static_class_name()))
  { 
    std::string id= value.id();
    std::multimap<std::string, size_t>::const_iterator iter= _figure_connections.find(id);
    std::multimap<std::string, size_t>::const_iterator end= _figure_connections.end();
    model_DiagramRef view(model_FigureRef::cast_from(value)->owner());

    // add connections from this figure to the list of children
    while (iter != end && iter->first == id)
    {
      model_ConnectionRef connection(view->connections()[iter->second]);
      char buffer[30];
      snprintf(buffer, sizeof(buffer), "/connections/%li", iter->second);
      FigureNode *conn= new FigureNode();
      conn->path= buffer;

      if (connection.is_instance(workbench_physical_Connection::static_class_name()))
        conn->name= workbench_physical_ConnectionRef::cast_from(connection)->caption();
      else
        conn->name= connection->name();
      conn->expandable= false;
      conn->color= "";
      conn->id= connection.id();
      conn->selected= _selected.find(conn->id) != _selected.end() ? 2 : 0;
      conn->is_layer= 0;
      conn->small_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(connection), Icon16);
      conn->large_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(connection), Icon48);

      node->subnodes.push_back(conn);

      ++iter;
    }
    return;
  }

  if (layer.is_valid())
  {
    for (size_t c= layer->figures().count(), i= 0; i < c; i++)
    {
      model_FigureRef figure(layer->figures().get(i));
      char buffer[50];
#ifdef __GNUC__
      snprintf(buffer, sizeof(buffer), "%sfigures/%zi", is_root?"/rootLayer/":"", i);
#else
      snprintf(buffer, sizeof(buffer), "%sfigures/%li", is_root?"/rootLayer/":"", i);
#endif
      FigureNode *child= new FigureNode();
      child->path= buffer;
      child->name= figure->name();
      child->expandable= _figure_connections.find(figure.id()) != _figure_connections.end();
      child->color= figure->layer()->color();
      child->id= figure.id();
      child->selected= _selected.find(child->id) != _selected.end() ? 2 : 0;
      child->is_layer= 0;
      child->small_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(figure), Icon16);
      child->large_icon= IconManager::get_instance()->get_icon_id(grt::ObjectRef(figure), Icon48);

      node->subnodes.push_back(child);

      FigureNode* figure_node = dynamic_cast<FigureNode*>(node);
      if (figure_node != NULL)
      {
        if (child->selected && figure_node->selected == 0)
          figure_node->selected= 1;
      }
    }
    std::sort(node->subnodes.begin(), node->subnodes.end(), sortnode());
  }
}



LayerTreeBE::LayerTreeBE(WBContext *wb)
: ValueTreeBE(wb->get_grt()), _wb(wb)
{
}


void LayerTreeBE::refresh()
{
  ValueTreeBE::refresh();
  refresh_selection_status();
}


void LayerTreeBE::refresh_node(const NodeId &node_id)
{
  FigureNode *node= dynamic_cast<FigureNode*>(get_node_for_id(node_id));
  
  if (node)
  {
    grt::ValueRef value= grt::get_value_by_path(get_root_value(), node->path);
    
    if (value.is_valid())
    {
      if (model_ObjectRef::can_wrap(value))
      {
        model_ObjectRef object(model_ObjectRef::cast_from(value));

        node->name= object->name();
        node->color= object->has_member("color") ? object->get_string_member("color") : "";
        node->selected= _selected.find(node->id) != _selected.end() ? 2 : 0;

        if (workbench_physical_ConnectionRef::can_wrap(value))
          node->name= workbench_physical_ConnectionRef::cast_from(value)->caption();
      }
    }
    else
      g_message("refresh node fail");
  }
}


bool LayerTreeBE::get_field(const bec::NodeId &node_id, int column, std::string &value)
{
  if (column == Selected)
  {
    FigureNode *node= dynamic_cast<FigureNode*>(get_node_for_id(node_id));
    if (node)
    {
      switch (node->selected)
      {
      case 0: value= ""; break;
      case 1: value= "x"; break;
      case 2: value= "X"; break;
      }
      return true;
    }
    return false;
  }    
  else if (column != Color)
    return bec::ValueTreeBE::get_field(node_id, column, value);
  else
  {
    FigureNode *node= dynamic_cast<FigureNode*>(get_node_for_id(node_id));
    if (node)
    {
      value= node->color;
      return true;
    }
    return false;
  }
}


bool LayerTreeBE::get_field(const bec::NodeId &node_id, int column, int &value)
{
  if (column == IsLayer)
  {
    FigureNode *node= dynamic_cast<FigureNode*>(get_node_for_id(node_id));
    value= 0;
    if (node)
    {
      value= node->is_layer;
      return true;
    }
  }
  return false;
}


void LayerTreeBE::rename_figure(const GrtObjectRef &object, const std::string &name)
{
  grt::AutoUndo undo(_grt);
  if (object.is_instance<workbench_physical_TableFigure>())
    workbench_physical_TableFigureRef::cast_from(object)->table()->name(name);
  else if (object.is_instance<workbench_physical_ViewFigure>())
    workbench_physical_ViewFigureRef::cast_from(object)->view()->name(name);
  else if (object.is_instance<workbench_physical_RoutineGroupFigure>())
    workbench_physical_RoutineGroupFigureRef::cast_from(object)->routineGroup()->name(name);
  else
    object->name(name);

  undo.end(strfmt(_("Rename to %s"), name.c_str()));
}


bool LayerTreeBE::set_field(const bec::NodeId &node_id, int column, const std::string &value)
{
  if (column == bec::ValueTreeBE::Name)
  {
    grt::ValueRef nvalue(get_node_value(node_id));

    if (nvalue.is_valid())
    {
      GrtObjectRef object(GrtObjectRef::cast_from(nvalue));

      rename_figure(object, value);
    }
    return true;
  }
  return false;
}


int LayerTreeBE::refresh_children_selection(std::vector<bec::ValueTreeBE::Node*> &children, const std::set<std::string> &selected)
{
  int count= 0;
  for (std::vector<bec::ValueTreeBE::Node*>::iterator iter= children.begin(); iter != children.end(); ++iter)
  {
    FigureNode* node= dynamic_cast<FigureNode*>(*iter);

    if (node)
    {
      if (selected.find(node->id) != selected.end())
      {
        node->selected= 2;
        count++;
      }
      else
        node->selected= 0;

      if (!node->subnodes.empty() && refresh_children_selection(node->subnodes, selected) < (int)node->subnodes.size())
      {
        if (node->is_layer && node->selected == 0)
          node->selected= 1;
      }
    }
  }
  return count;
}


void LayerTreeBE::refresh_selection_status()
{
  if (get_root_value().is_valid())
  {
    model_DiagramRef view(model_DiagramRef::cast_from(get_root_value()));

    grt::ListRef<model_Object> selection(view->selection());

    _selected.clear();
    for (size_t c= selection.count(), i= 0; i < c; i++)
      _selected.insert(selection.get(i).id());

    refresh_children_selection(_root.subnodes, _selected);
  }
}


bool LayerTreeBE::activate_node(const NodeId &node_id)
{
  grt::ValueRef value(get_node_value(node_id));
  if (value.is_valid())
  {
    select_object(value);
    return true;
  }
  return false;
}


void LayerTreeBE::select_object(const grt::ValueRef &value)
{
  ModelDiagramForm *form= 0;
  if (model_FigureRef::can_wrap(value))
  {
    model_FigureRef figure(model_FigureRef::cast_from(value));
    form= _wb->get_model_context()->get_diagram_form_for_diagram_id(figure->owner().id());
    if (form)
      form->focus_and_make_visible(figure, true);
  }
  else if (model_ConnectionRef::can_wrap(value))
  {
    model_ConnectionRef conn(model_ConnectionRef::cast_from(value));
    ModelDiagramForm *form= _wb->get_model_context()->get_diagram_form_for_diagram_id(conn->owner().id());
    if (form)
      form->focus_and_make_visible(conn, true);
  }
  else if (model_LayerRef::can_wrap(value))
  {
    model_LayerRef layer(model_LayerRef::cast_from(value));
    ModelDiagramForm *form= _wb->get_model_context()->get_diagram_form_for_diagram_id(layer->owner().id());
    if (form)
      form->focus_and_make_visible(layer, true);
  }
}


bec::MenuItemList LayerTreeBE::get_popup_items_for_nodes(const std::vector<bec::NodeId> &nodes)
{
  bool has_connections = false;
  
  for (int i = nodes.size() - 1; i >= 0; --i)
  {
    grt::ValueRef value(get_node_value(nodes[i]));
    if (model_ConnectionRef::can_wrap(value))
    {   
      has_connections = true;
      break;
    }
  }

  bec::MenuItemList items;
  bec::MenuItem item;
  item.caption = _("Select in Diagram");
  item.name    = "select";
  item.enabled = nodes.size() > 0;
  items.push_back(item);

  item.caption = _("Edit Object");
  item.name    = "edit";
  item.enabled = nodes.size() == 1 && model_ObjectRef::can_wrap(get_node_value(nodes[0]));
  items.push_back(item);
  
  if (has_connections)
  {
    item.caption = _("Reveal");
    item.name    = "reveal";
    item.enabled = true; // TODO: Make it enabled if connection is hidden
    items.push_back(item);
  }
  
  return items;
}

bool LayerTreeBE::activate_popup_item_for_nodes(const std::string &name, const std::vector<bec::NodeId> &unsorted_nodes)
{
  std::vector<bec::NodeId> nodes(unsorted_nodes);
  std::sort(nodes.begin(), nodes.end());
  
  if (name == "select")
  {
    for (std::vector<bec::NodeId>::const_iterator iter= nodes.begin(); iter != nodes.end(); ++iter)
    {
      activate_node(*iter);
    }
  }
  else if (name == "edit")
  {
    if (!nodes.empty())
    {
      grt::ValueRef value(get_node_value(nodes[0]));
      if (model_ObjectRef::can_wrap(value))
        _wb->get_model_context()->activate_canvas_object(model_ObjectRef::cast_from(value), 0);
    }
  }
  else if (name == "reveal")
  {
    for (int i = nodes.size() - 1; i >= 0; --i)
    {
      grt::ValueRef value(get_node_value(nodes[i]));

      if (model_ConnectionRef::can_wrap(value))
      {
        model_ConnectionRef conn = model_ConnectionRef::cast_from(value);
        conn->visible(1);
        conn->drawSplit(0);
      }
    }
  }
  else
    return false;

  return true;
}
