#include "stdafx.h"

#include "diff/diffchange.h"
#include "diff/grtdiff.h"
#include "diff/changeobjects.h"
#include "diff/changelistobjects.h"

#include "diff_tree.h"
#include "grts/structs.model.h"

#include <fstream>
#include <set>

#include "grtdb/catalog_templates.h"

//using namespace wb;
using namespace bec;

std::string utf_to_upper(const char *str)
{
  char *n= g_utf8_strup(str, g_utf8_strlen(str, -1));
  std::string retval(n);
  g_free(n);
  return retval;
}

namespace
{
  struct Output {
    std::ostream& ostream;
    Output(std::ostream& os) : ostream(os) {}
    void operator () (const DiffNode *node) { ostream << *node; }
  };
}

std::ostream& operator << (std::ostream& os, const DiffNode& node)
{
  os << "\n<diffnode is_modified='" << (node.is_modified() ? 1 : 0) << "'";

  if(node.get_model_part().is_valid_object())
    os << " model_name='" << node.get_model_part().get_name() << "'";
  if(node.get_db_part().is_valid_object())
    os << " db_name='" << node.get_db_part().get_name() << "'";
  if(node.get_application_direction() == DiffNode::ApplyToModel)
    os << "dir='model'";
  else if(node.get_application_direction() == DiffNode::ApplyToDb)
    os << "dir='db'";
  else if(node.get_application_direction() == DiffNode::DontApply)
    os << "dir='dontapply'";
  
  os << " >";
  

  std::for_each(node.get_children_begin(), node.get_children_end(), Output(os));

  os << "\n</diffnode>";
  return os;
}

namespace
{
  struct CompareName
  {
    std::string name;

    CompareName(const std::string& n)
      : name(utf_to_upper(n.c_str())) {}

    bool operator () (const DiffNode *node) 
    { 
      if(!node->get_db_part().is_valid_object())
        return false;

      std::string node_name(
        utf_to_upper(node->get_db_part().get_name().c_str()));

      return (name.compare(node_name) == 0);     }
  };
}

DiffNode *DiffNode::find_child_by_db_part_name(const std::string& name)
{

  if(this == NULL)
    throw new std::logic_error("invalid object name");

  DiffNodeVector::const_iterator b= children.begin();
  DiffNodeVector::const_iterator e= children.end();
  DiffNodeVector::const_iterator it= std::find_if(b, e, CompareName(name));
  if(it == e)
    return NULL;
  return *it;
}

void DiffNode::set_next_apply_direction()
{
  switch(applyDirection)
  {
  case ApplyToModel:
    applyDirection= ApplyToDb;
    break;
  case ApplyToDb:
    applyDirection= DontApply;
    break;
  case DontApply:
    applyDirection= ApplyToModel;
    break;
  }
}


void DiffNode::set_apply_direction(ApplicationDirection dir)
{
  applyDirection= dir;
}


namespace
{
  struct GetObjectListForScript
  {
    std::vector<grt::ValueRef>& vec;

    GetObjectListForScript(std::vector<grt::ValueRef>& v) : vec(v) {}
    void operator () (const DiffNode *node) { node->get_object_list_for_script(vec); }
  };

  struct NullModelPart
  {
    bool operator() (const DiffNode *node) { return node->get_model_part().get_object().is_valid() == 0; }
  };
}

void DiffNode::get_object_list_for_script(std::vector<grt::ValueRef>& vec) const
{

  bool im_already_there= false;
  
  if(applyDirection == ApplyToDb)
  {
    if(this->get_model_part().get_object().is_valid())
    {
      vec.push_back(this->get_model_part().get_object());
    }
    else
    {
      vec.push_back(this->get_db_part().get_object());
      return;
    }

    im_already_there= true;
  }

  DiffNodeVector::const_iterator b= children.begin();
  DiffNodeVector::const_iterator e= children.end();
  
  if(!im_already_there)
  {
    if(std::find_if(b, e, NullModelPart()) != e)
      vec.push_back(this->get_model_part().get_object());
  }

  std::for_each(b, e, GetObjectListForScript(vec));
}

namespace
{
  struct GetObjectListToApplyToModel
  {
    std::vector<grt::ValueRef>& vec;
    GetObjectListToApplyToModel(std::vector<grt::ValueRef>& v) : vec(v) {}
    void operator () (const DiffNode *node) { node->get_object_list_to_apply_to_model(vec); }
  };
}

void DiffNode::get_object_list_to_apply_to_model(std::vector<grt::ValueRef>& vec) const
{

  if(applyDirection == ApplyToModel)
    vec.push_back(this->get_db_part().get_object());

  DiffNodeVector::const_iterator b= children.begin();
  DiffNodeVector::const_iterator e= children.end();
  std::for_each(b, e, GetObjectListToApplyToModel(vec));
}

void DiffNode::set_modified_and_update_dir(bool m)
{
  modified= m;
  applyDirection= m ? ApplyToDb : CantApply;
}

std::string get_old_name_or_name(GrtNamedObjectRef obj)
{
  if(!obj.is_valid())
    return "";

  if(strlen(obj->oldName().c_str()))
    return std::string(obj->oldName().c_str());
  return std::string(obj->name().c_str());
}

template<>
std::string get_catalog_map_key<db_mysql_Catalog>(db_mysql_CatalogRef cat)
{
  if (!cat.is_valid())
    return "default";
  return std::string("`").append(cat->name()).append("`");
}

template<class _Object>
class ObjectAction
{
protected:
  CatalogMap& map;

public:
  ObjectAction(CatalogMap& m) : map(m) {}

  virtual void operator() (_Object object)
  {
    map[get_catalog_map_key(object)]= object;
  }
};

namespace
{
  struct TableAction : public ObjectAction<db_mysql_TableRef>
  {
  public:
    TableAction(CatalogMap& m) : ObjectAction<db_mysql_TableRef>(m) {}

    virtual void operator() (db_mysql_TableRef table)
    {
      ObjectAction<db_mysql_TableRef>::operator() (table);
      ObjectAction<db_mysql_ColumnRef>  oa_column(map);
      ct::for_each<ct::Columns>(table, oa_column);
      
      ObjectAction<db_mysql_IndexRef> oa_index(map);
      ct::for_each<ct::Indices>(table, oa_index);
      
      ObjectAction<db_mysql_TriggerRef> oa_trigger(map);
      ct::for_each<ct::Triggers>(table, oa_trigger);
      
      ObjectAction<db_mysql_ForeignKeyRef> oa_fk(map);
      ct::for_each<ct::ForeignKeys>(table, oa_fk);
    }
  };

  struct SchemaAction : public ObjectAction<db_mysql_SchemaRef>
  {
  public:
    SchemaAction(CatalogMap& m) : ObjectAction<db_mysql_SchemaRef>(m) {}

    virtual void operator() (db_mysql_SchemaRef schema)
    {
      ObjectAction<db_mysql_SchemaRef>::operator() (schema);
      
      TableAction ta(map);
      ct::for_each<ct::Tables>(schema, ta);
      
      ObjectAction<db_mysql_ViewRef> oa_view(map);
      ct::for_each<ct::Views>(schema, oa_view);
      
      ObjectAction<db_mysql_RoutineRef> oa_routine(map);
      ct::for_each<ct::Routines>(schema, oa_routine);
    }
  };
}

WBPLUGINDBMYSQLBE_PUBLIC_FUNC
void build_catalog_map(db_mysql_CatalogRef catalog, CatalogMap& map)
{
   SchemaAction sa(map);
  ct::for_each<ct::Schemata>(catalog, sa);
}

template<typename T>
T DiffTreeBE::find_object_in_catalog_map(T t, const CatalogMap& map)
{
  if (strlen(t->oldName().c_str()) == 0)
    return T();
  CatalogMap::const_iterator iter= map.find(get_catalog_map_key(t));
  if (iter != map.end())
    return T::cast_from(iter->second);
  return T();
}

void DiffTreeBE::fill_tree(DiffNode *table_node, db_mysql_TableRef table, const CatalogMap& map, bool inverse)
{
  // triggers
  for(size_t k= 0, triggers_count= table->triggers().count(); k < triggers_count; k++)
  {
    db_mysql_TriggerRef trigger= table->triggers().get(k);
    db_mysql_TriggerRef external_trigger= find_object_in_catalog_map(trigger, map);
    DiffNode *trigger_node= new DiffNode(trigger, external_trigger, inverse);
    table_node->append(trigger_node);
  }
}

void DiffTreeBE::fill_tree(DiffNode *schema_node, db_mysql_SchemaRef schema, const CatalogMap& map, bool inverse)
{
  // tables
  for(size_t j= 0, tables_count= schema->tables().count(); j < tables_count; j++)
  {
    db_mysql_TableRef table= schema->tables().get(j);
    db_mysql_TableRef external_table= find_object_in_catalog_map(table, map);
    DiffNode *table_node= new DiffNode(table, external_table, inverse);
    schema_node->append(table_node);
    fill_tree(table_node, table, map, inverse);
  }

  // views
  for(size_t j= 0, views_count= schema->views().count(); j < views_count; j++)
  {
    db_mysql_ViewRef view= schema->views().get(j);
    db_mysql_ViewRef external_view= find_object_in_catalog_map(view, map);
    DiffNode *view_node= new DiffNode(view, external_view, inverse);
    schema_node->append(view_node);
  }
  
  // routines
  for(size_t j= 0, routines_count= schema->routines().count(); j < routines_count; j++)
  {
    db_mysql_RoutineRef routine= schema->routines().get(j);
    db_mysql_RoutineRef external_routine= find_object_in_catalog_map(routine, map);
    DiffNode *routine_node= new DiffNode(routine, external_routine, inverse);
    schema_node->append(routine_node);
  }
}

void DiffTreeBE::fill_tree(DiffNode *root, db_mysql_CatalogRef model_catalog, const CatalogMap& map, bool inverse)
{
  for(size_t i= 0, schemata_count= model_catalog->schemata().count(); i < schemata_count; i++)
  {
    db_mysql_SchemaRef schema= model_catalog->schemata().get(i);
    db_mysql_SchemaRef external_schema= find_object_in_catalog_map(schema, map);
    if(!external_schema.is_valid())
    {
      std::string schema_name(schema->name().c_str());
      if(std::find(_schemata.begin(), _schemata.end(), schema_name) != _schemata.end())
        continue;
    }
    DiffNode *schema_node= new DiffNode(schema, external_schema, inverse);
    root->append(schema_node);
    fill_tree(schema_node, schema, map, inverse);
  }
}

void DiffTreeBE::build_diff_item_list(const DiffChange* diffchange, DiffTreeBE::DiffItemList& list, DiffTreeBE::ModifiedObjectStack& workstack)
{
  switch(diffchange->get_change_type())
  {
  case SimpleValue:
    {
      if(!workstack.empty())
        list.push_back(DiffItem(workstack.top(), DiffTreeBE::DiffItemModified));
    }
    break;

  case grt::ListItemAdded:
    {
      grt::ValueRef v= static_cast<const grt::ListItemAddedChange *>(diffchange)->get_added_object();

      bool dont_push= 
        (db_SchemaRef::can_wrap(v) || db_TableRef::can_wrap(v) 
        || db_ViewRef::can_wrap(v) || db_RoutineRef::can_wrap(v) 
        || db_TriggerRef::can_wrap(v));

      if(!dont_push && !workstack.empty())
        list.push_back(DiffItem(workstack.top(), DiffTreeBE::DiffItemModified));
    }
    break;

  case grt::ListItemRemoved:
    list.push_back(
      DiffItem(
        grt::ValueRef(static_cast<const grt::ListItemRemovedChange *>(diffchange)->get_action().first), 
        DiffTreeBE::DiffItemRemoved));
    break;

  case grt::ObjectModified:
    {
      for(grt::ChangeSet::const_iterator e= diffchange->subchanges()->end(), it= diffchange->subchanges()->begin(); it != e; it++)
        build_diff_item_list(*it, list, workstack);
    }
    break;
  
  case grt::ObjectAttrModified:
    build_diff_item_list(static_cast<const grt::ObjectAttrModifiedChange *>
      (diffchange)->get_subchange(), list, workstack);
    break;

  case grt::ListModified:
    {
      for(grt::ChangeSet::const_iterator e= diffchange->subchanges()->end(), 
        it= diffchange->subchanges()->begin(); it != e; it++)
        build_diff_item_list(*it, list, workstack);
    }
    break;

  case grt::ListItemModified:
    {
      grt::ValueRef v(static_cast<const grt::ListItemModifiedChange *>
        (diffchange)->get_action().first.first);

      bool push= 
        (db_SchemaRef::can_wrap(v) || db_TableRef::can_wrap(v) 
        || db_ViewRef::can_wrap(v) || db_RoutineRef::can_wrap(v) 
        || db_TriggerRef::can_wrap(v));

      if(push)
        workstack.push(v);
      build_diff_item_list(*static_cast<const grt::ListItemModifiedChange *>
        (diffchange)->subchanges()->begin(), list, workstack);
      if(push)
        workstack.pop();
    }
    break;

  case grt::ListItemOrderChanged:
    {
      const grt::ListItemOrderChange *oc= 
        static_cast<const grt::ListItemOrderChange *>(diffchange);
      grt::ValueRef v(oc->get_action().first.first);
      if(db_ColumnRef::can_wrap(v) || db_IndexColumnRef::can_wrap(v))
        list.push_back(DiffItem(workstack.top(), DiffTreeBE::DiffItemModified));
      // the list item order change action can have a nested
      // object-modified action
      if(db_TableRef::can_wrap(v) && !oc->subchanges()->empty())
        list.push_back(DiffItem(v, DiffTreeBE::DiffItemModified));
      if(db_SchemaRef::can_wrap(v) && !oc->subchanges()->empty())
        build_diff_item_list(*oc->subchanges()->begin(), list, workstack);
    }
    break;

  default:
    break;
  }
}

void DiffTreeBE::update_tree_from_diff_item_list(DiffNode *root, const DiffTreeBE::DiffItemList& worklist)
{
  for(DiffTreeBE::DiffItemList::const_iterator e= worklist.end(), it= worklist.begin(); it != e; it++)
  {
    grt::ValueRef value= it->object;

    if(db_mysql_SchemaRef::can_wrap(value))
    {
      db_mysql_SchemaRef schema= db_mysql_SchemaRef::cast_from(value);
      DiffNode *schema_node= NULL;
      //if(it->action == DiffItemAdded)
      if(it->action == DiffItemRemoved)
      {
        schema_node= new DiffNode(db_mysql_SchemaRef(), schema, false);
        root->append(schema_node);
        fill_tree(schema_node, schema, CatalogMap(), true);
      }
      else if(it->action == DiffItemModified)
      {
        schema_node= root->find_child_by_db_part_name(std::string(schema->oldName().c_str()));
        schema_node->set_modified_and_update_dir(true);
      }
    }
    else if(db_mysql_TableRef::can_wrap(value))
    {
      db_mysql_TableRef table= db_mysql_TableRef::cast_from(value);
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(table->owner())->oldName().c_str()));
      DiffNode *table_node= NULL;
      //if(it->action == DiffItemAdded)
      if(it->action == DiffItemRemoved)
      {
        table_node= new DiffNode(db_mysql_TableRef(), table, false);
        schema_node->append(table_node);
        fill_tree(table_node, table, CatalogMap(), true);
      }
      else if(it->action == DiffItemModified)
      {
        table_node= schema_node->find_child_by_db_part_name(std::string(table->oldName().c_str()));
        table_node->set_modified_and_update_dir(true);
      }
    }
    else if(db_mysql_ViewRef::can_wrap(value))
    {
      db_mysql_ViewRef view= db_mysql_ViewRef::cast_from(value);
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(view->owner())->oldName().c_str()));
      DiffNode *view_node= NULL;
      //if(it->action == DiffItemAdded)
      if(it->action == DiffItemRemoved)
      {      
        view_node= new DiffNode(db_mysql_ViewRef(), view, false);
        schema_node->append(view_node);
      }
      else if(it->action == DiffItemModified)
      {
        view_node= schema_node->find_child_by_db_part_name(std::string(view->oldName().c_str()));
        view_node->set_modified_and_update_dir(true);
      }
    }
    else if(db_mysql_RoutineRef::can_wrap(value))
    {
      db_mysql_RoutineRef routine= db_mysql_RoutineRef::cast_from(value);
      DiffNode *routine_node= NULL;
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(routine->owner())->oldName().c_str()));
      //if(it->action == DiffItemAdded)
      if(it->action == DiffItemRemoved)
      {
        routine_node= new DiffNode(db_mysql_RoutineRef(), routine, false);
        schema_node->append(routine_node);
      }
      else if(it->action == DiffItemModified)
      {
        routine_node= schema_node->find_child_by_db_part_name(std::string(routine->oldName().c_str()));
        routine_node->set_modified_and_update_dir(true);
      }
    }
    else if(db_ColumnRef::can_wrap(value))
    {
      db_ColumnRef column= db_ColumnRef::cast_from(value);
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(column->owner()->owner())->oldName().c_str()));
      DiffNode *table_node= schema_node->find_child_by_db_part_name(std::string(db_mysql_TableRef::cast_from(column->owner())->oldName().c_str()));
      table_node->set_modified_and_update_dir(true);
    }
    else if(db_mysql_IndexRef::can_wrap(value))
    {
      db_mysql_IndexRef index= db_mysql_IndexRef::cast_from(value);
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(index->owner()->owner())->oldName().c_str()));
      DiffNode *table_node= schema_node->find_child_by_db_part_name(std::string(db_mysql_TableRef::cast_from(index->owner())->oldName().c_str()));
      table_node->set_modified_and_update_dir(true);
    }
    else if(db_mysql_IndexColumnRef::can_wrap(value))
    {
      db_mysql_IndexColumnRef index_col= db_mysql_IndexColumnRef::cast_from(value);
      db_mysql_IndexRef index= db_mysql_IndexRef::cast_from(index_col->owner());
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(index->owner()->owner())->oldName().c_str()));
      DiffNode *table_node= schema_node->find_child_by_db_part_name(std::string(db_mysql_TableRef::cast_from(index->owner())->oldName().c_str()));
      table_node->set_modified_and_update_dir(true);
    }
    else if(db_mysql_ForeignKeyRef::can_wrap(value))
    {
      db_mysql_ForeignKeyRef fk= db_mysql_ForeignKeyRef::cast_from(value);
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(fk->owner()->owner())->oldName().c_str()));
      DiffNode *table_node= schema_node->find_child_by_db_part_name(std::string(db_mysql_TableRef::cast_from(fk->owner())->oldName().c_str()));
      table_node->set_modified_and_update_dir(true);
    }
    else if(db_mysql_TriggerRef::can_wrap(value))
    {
      db_mysql_TriggerRef trigger= db_mysql_TriggerRef::cast_from(value);
      DiffNode *trigger_node= NULL;
      DiffNode *schema_node= root->find_child_by_db_part_name(std::string(db_mysql_SchemaRef::cast_from(trigger->owner()->owner())->oldName().c_str()));
      DiffNode *table_node= schema_node->find_child_by_db_part_name(std::string(db_mysql_TableRef::cast_from(trigger->owner())->oldName().c_str()));
      if(it->action == DiffItemRemoved)
      //if(it->action == DiffItemAdded)
      {
        trigger_node= new DiffNode(db_mysql_TriggerRef(), trigger, false);
        table_node->append(trigger_node);
      }
      else if(it->action == DiffItemModified)
      {
        trigger_node= table_node->find_child_by_db_part_name(std::string(trigger->oldName().c_str()));
        trigger_node->set_modified_and_update_dir(true);
      }
    }
  }
}

#ifdef _WIN32
#include <windows.h>
#endif

DiffTreeBE::DiffTreeBE(const std::vector<std::string>& schemata,
                       db_mysql_CatalogRef model_catalogRef, 
                       db_mysql_CatalogRef external_catalog, 
                       DiffChange* diffchange)
{
  _root= new DiffNode(model_catalogRef, external_catalog, false);
  _schemata.assign(schemata.begin(), schemata.end());
  
  CatalogMap map;
  build_catalog_map(external_catalog, map);
  fill_tree(_root, model_catalogRef, map, false);
  
  DiffItemList diffitemlist;
  ModifiedObjectStack workstack;

  if(diffchange)
  {
    build_diff_item_list(diffchange, diffitemlist, workstack);
    update_tree_from_diff_item_list(_root, diffitemlist);
  }

  change_nothing_icon= bec::IconManager::get_instance()->get_icon_id("change_nothing.png");
  change_backward_icon= bec::IconManager::get_instance()->get_icon_id("change_backward.png");
  change_forward_icon= bec::IconManager::get_instance()->get_icon_id("change_forward.png");
  change_ignore_icon= bec::IconManager::get_instance()->get_icon_id("change_ignore.png");
  alert_icon= bec::IconManager::get_instance()->get_icon_id("alert_thin.png");
}

DiffNode *DiffTreeBE::get_node_with_id(const NodeId &nodeid)
{
  DiffNode *n= _root;
  int i;

  if (!n)
    return NULL;

  if (nodeid.depth() == 0)
    return n;

  for (i= 0; i < nodeid.depth(); i++)
  {
    if (nodeid[i] >= (int)n->get_children_size())
      throw std::logic_error("Invalid node id");

    n= n->get_child(nodeid[i]);
  }
  return n;
}

int DiffTreeBE::count_children(const bec::NodeId &nodeid)
{
  DiffNode *node= get_node_with_id(nodeid);
  if(node)
    return (int)node->get_children_size();
  return 0;
}

bec::NodeId DiffTreeBE::get_child(const bec::NodeId &parentid, int child_idx)
{
  DiffNode *node= get_node_with_id(parentid);
  
  if (node && child_idx < (int)node->get_children_size())
    return NodeId(parentid).append(child_idx);
  
  if (node)
    throw std::logic_error("invalid index");

  return NodeId();
}

bool DiffTreeBE::get_field(const bec::NodeId &node_id, int column, std::string &value)
{
  if ((column != ModelObjectName)
   && (column != DbObjectName))
  {
    return false;
  }

  DiffNode *node= dynamic_cast<DiffNode *>(get_node_with_id(node_id));
  if(!node)
    return false;

  switch(column)
  {
  case ModelObjectName:
    if(node->get_model_part().is_valid_object())
      value= node->get_model_part().get_name();
    else
      value= "N/A";
    break;
  case DbObjectName:
    if(node->get_db_part().is_valid_object())
      value= node->get_db_part().get_name();
    else
      value= "N/A";
    break;
  default:
    value= "";
    return false;
  }

  return true;
}

bec::IconId DiffTreeBE::get_field_icon(const bec::NodeId &node_id, int column, IconSize size)
{
  if ((column != ModelObjectName)
   && (column != ModelChanged) 
   && (column != ApplyDirection)
   && (column != DbChanged)
   && (column != DbObjectName))
  {
    return -1;
  }

  DiffNode *node= dynamic_cast<DiffNode *>(get_node_with_id(node_id));
  if(!node)
    return -1;

  IconId object_icon= 1;
  if(node->get_db_part().is_valid_object())
    object_icon= bec::IconManager::get_instance()->get_icon_id(node->get_db_part().get_object());
  else if(node->get_model_part().is_valid_object())
    object_icon= bec::IconManager::get_instance()->get_icon_id(node->get_model_part().get_object());

  switch(column)
  {
  case ModelChanged:
    return (node->is_modified()) ? alert_icon : 0;
  case ModelObjectName:
    return object_icon;
  case ApplyDirection:
    switch(node->get_application_direction())
    {
    case DiffNode::ApplyToModel:
      return change_backward_icon;
    case DiffNode::ApplyToDb:
      return change_forward_icon;
    case DiffNode::DontApply:
      return change_ignore_icon;
    case DiffNode::CantApply:
      return change_nothing_icon;
    }
    return -1;
  case DbObjectName:
    return (node->is_modified()) ? alert_icon : 0;
  default:
    return -1;
  }
}

void DiffTreeBE::set_next_apply_direction(const bec::NodeId &node_id)
{
  DiffNode *node= dynamic_cast<DiffNode *>(get_node_with_id(node_id));
  if(node)
    node->set_next_apply_direction();
}

void DiffTreeBE::set_apply_direction(const bec::NodeId &node_id, DiffNode::ApplicationDirection dir)
{
  DiffNode *node= dynamic_cast<DiffNode *>(get_node_with_id(node_id));
  if(node)
    node->set_apply_direction(dir);
}


void DiffTreeBE::get_object_list_for_script(std::vector<grt::ValueRef>& vec) const
{
  _root->get_object_list_for_script(vec);
}

void DiffTreeBE::get_object_list_to_apply_to_model(std::vector<grt::ValueRef>& vec) const
{
  _root->get_object_list_to_apply_to_model(vec);
}

//void DiffTreeBE::sync_old_name() const
//{
//  _root->sync_old_name();
//}
