// Copyright (C) 2001 Jean-Marc Valin

#include "GUINode.h"
#include "GUINetwork.h"
#include "Node.h"
#include "GUIDocument.h"
#include "GUITerminal.h"
#include "GUINodeParameters.h"
#include "GUILink.h"
#include "GUINetTerminal.h"
#include "GUINodeTooltip.h"
#include "flow_pref.h"
#include <math.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "vflow.h"

using namespace std;

namespace FD {

static gint node_handler (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
{
   return ((GUINode *)(data))->event(event);
}

int theTime;


GUINode::GUINode(UINetwork* _net, string _name, string _type, double _x, double _y)
   : UINode(_net, _name, _type, _x, _y, false)
   , dragging(false)
   , grab(false)
{

  parameters = newNodeParameters(this,type);
  initialize_widgets();
  createPopup();
}


GUINode::GUINode(UINetwork* _net, xmlNodePtr def)
   : UINode(_net, def,false), dragging(false) , grab(false) 
{

    //TODO use loadXML function instead of reimplementing xml loading here!
    //loadXML(def);
    char *str_name = (char *)xmlGetProp(def, (xmlChar *)"name");
    char *str_type = (char *)xmlGetProp(def, (xmlChar *)"type");
    char *str_x = (char *)xmlGetProp(def, (xmlChar *)"x");
    char *str_y = (char *)xmlGetProp(def, (xmlChar *)"y");
    
    if (!str_name || !str_type || !str_x || !str_y)
    {
        throw new GeneralException("Missing node parameter(s) in XML definition", __FILE__, __LINE__);
    }
    
    name = string(str_name);
    type = string(str_type);
    x = atof(str_x);
    y = atof(str_y);
    
    free (str_name); free (str_type); free(str_x); free(str_y);

    xtmp = x;
    ytmp = y;

    description = net->getDocument()->getDescription(type);
    
    parameters = newNodeParameters(this, type);
    initialize_widgets();
    parameters->load(def);
    createPopup();
}

GUINode::~GUINode()
{
   dynamic_cast<GUINetwork*>(net)->removeSelectedNode(this);

   for (int i=0;i<inputs.size();i++) {
     //cerr<<"GUINode::~GUINode("<<getName()<<")"<< "deleting input name "<<inputs[i]->getName()<<endl;
     delete inputs[i];
      
   }

   for (int i=0;i<outputs.size();i++) {
     //cerr<<"GUINode::~GUINode("<<getName()<<")"<<  "deleting output name "<<outputs[i]->getName()<<endl;
     delete outputs[i];
     
   }
   
   //parameters will be deleted in UINode destructor
   //delete parameters;
   net->removeNode(this);
   gtk_object_destroy(GTK_OBJECT(group));
   destroyed=true;
}
/*
static void node_add_input (GtkMenuItem *menuitem, GUINode *node)
{
   char *input_name = "INTPUT-N";
   node->addTerminal(string(input_name), UINetTerminal::INPUT);
}

static void node_add_output (GtkMenuItem *menuitem, GUINode *node)
{
   char *output_name = "OUTPUT-N";
   node->addTerminal(string(output_name), UINetTerminal::OUTPUT);
}
*/

static void node_help (GtkMenuItem *menuitem, gpointer user_data)
{
   ((GUINode *)(user_data))->help();
}

static void node_prop (GtkMenuItem *menuitem, gpointer user_data)
{
   ((GUINode *)(user_data))->propertiesShow();
}

static void node_delete (GtkMenuItem *menuitem, gpointer user_data)
{

  GUINode* my_node = reinterpret_cast<GUINode*>(user_data);
  GUINetwork* my_net = dynamic_cast<GUINetwork*>(my_node->getNetwork());

  //delete all selected nodes...
  if (my_net) {    
    if (my_net->isNodeSelected(my_node)) {
      my_net->clearSelectedNodes();
    }
    else {
      delete my_node;
    }
  }
  else {
    delete my_node;
  }
}


void GUINode::propertiesShow()
{

  GUINodeParameters *my_params = dynamic_cast<GUINodeParameters*>(parameters);
  
  if (my_params) {
    my_params->show();
  }
      
}

void GUINode::help()
{
   string fullPath = UIDocument::findExternal(type + ".cc", "VFLOW_SOURCE", false);
   if (fullPath == "")
      fullPath = UIDocument::findExternal(type + ".cpp", "VFLOW_SOURCE", false);
   //FIXME: gnome 2
   /*if (fullPath == "")
      cerr << "Node help not found\n";
   else
      gnome_help_goto(NULL, const_cast<char *>(fullPath.c_str()));
      */
}

void GUINode::createPopup()
{
   popupMenu = gtk_menu_new();
   GtkWidget *label;
   /*
   label = gtk_menu_item_new_with_label("Add input");
   gtk_menu_append(GTK_MENU(popupMenu),label);
   gtk_widget_show(label);
   gtk_widget_ref (label);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             label,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_signal_connect(GTK_OBJECT(label), "activate",
                      (GtkSignalFunc) node_add_input,
                      this);

   label = gtk_menu_item_new_with_label("Add output");
   gtk_menu_append(GTK_MENU(popupMenu),label);
   gtk_widget_show(label);
   gtk_widget_ref (label);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             label,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_signal_connect(GTK_OBJECT(label), "activate",
                      (GtkSignalFunc) node_add_output,
                      this);
   */
   label = gtk_menu_item_new_with_label("Properties");
   gtk_menu_append(GTK_MENU(popupMenu),label);
   gtk_widget_show(label);
   gtk_widget_ref (label);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             label,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_signal_connect(GTK_OBJECT(label), "activate",
                      (GtkSignalFunc) node_prop,
                      this);


   label = gtk_menu_item_new_with_label("Help");
   gtk_menu_append(GTK_MENU(popupMenu),label);
   gtk_widget_show(label);
   gtk_widget_ref (label);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             label,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_signal_connect(GTK_OBJECT(label), "activate",
                      (GtkSignalFunc) node_help,
                      this);
   
   
   GtkWidget *separ = gtk_menu_item_new();
   gtk_menu_append(GTK_MENU(popupMenu),separ);
   gtk_widget_show(separ);
   gtk_widget_ref (separ);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             separ,
                             (GtkDestroyNotify) gtk_widget_unref);

   label = gtk_menu_item_new_with_label("Delete");
   gtk_menu_append(GTK_MENU(popupMenu),label);
   gtk_widget_show(label);
   gtk_widget_ref (label);
   gtk_object_set_data_full (GTK_OBJECT (popupMenu), "label",
                             label,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_signal_connect(GTK_OBJECT(label), "activate",
                      (GtkSignalFunc) node_delete,
                      this);


}

void GUINode::doGrab()
{
   GdkCursor *fleur;
   GnomeCanvasItem *item=GNOME_CANVAS_ITEM(group);
   xtmp = x;
   ytmp = y;
   
   fleur = gdk_cursor_new(GDK_FLEUR);
   gnome_canvas_item_grab(item,
                          GDK_POINTER_MOTION_MASK | 
                          GDK_BUTTON_RELEASE_MASK |
                          GDK_BUTTON_PRESS_MASK,
                          //GDK_ALL_EVENTS_MASK,
                          fleur,
                          0);
   gdk_cursor_destroy(fleur);
   dragging = TRUE;
   grab=true;
}


gint GUINode::event(GdkEvent *event)
{
   // static double x, y;
   double new_x, new_y;
   GdkCursor *fleur;
   //static int dragging;
   double item_x, item_y;

   GnomeCanvasItem *item=GNOME_CANVAS_ITEM(group);
   item_x = event->button.x;
   item_y = event->button.y;
   gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
   //cerr << "+";

   NodeInfo *my_info = getNetwork()->getDocument()->getRepository().findNode(getType());

   switch (event->type) 
   {
   case GDK_BUTTON_PRESS:

     //cerr<<"GUINode button event"<<endl;

      switch(event->button.button) 
      {
      case 1:
	
         if (event->button.state & GDK_SHIFT_MASK)
         {
            //dynamic_cast<GUINodeParameters *> (parameters)->show();
	   //delete this;
	   
	   //cloning...
	   //creating new node
	   GUINetwork *my_net = dynamic_cast<GUINetwork*>(net);

	   GUINode *my_node = dynamic_cast<GUINode*>(my_net->addNode(getType(),item_x + 10,item_y + 10));

	   //copying parameters
	   UINodeParameters *params_source = getParameters() ;


	   //copying inputs (for resizable nodes)
	   std::vector<UITerminal *> all_inputs = getInputs();
	   for (int i = 0; i < all_inputs.size(); i++) {
	     string input_name = all_inputs[i]->getName();
	     string input_type = all_inputs[i]->getType();
	     if (my_node->getInputNamed(input_name) == NULL) {
	       //add this input
	       my_node->addTerminal(string(input_name), UINetTerminal::INPUT);
	     }
	   }
	   
	   
	   //copying outputs (for resizable nodes)
	   std::vector<UITerminal *> all_outputs = getOutputs();
	   
	   for (int i = 0; i < all_outputs.size(); i++) {
	     string output_name = all_outputs[i]->getName();
	     string output_type = all_outputs[i]->getType();
	     if (my_node->getOutputNamed(output_name) == NULL) {
	       //add this output
	       my_node->addTerminal(string(output_name), UINetTerminal::OUTPUT);
	     }
	   }
	   


	   //FIXME : PROBABLE LEAK.

	   UINodeParameters *params_destination = new GUINodeParameters(my_node,getType());
	   
	   params_destination->copyParameterText(params_source);

	   my_node->setNodeParameters(params_destination);

	   return true;
         }
	 else if (event->button.state & GDK_CONTROL_MASK) {


	 } else 
	   {
            if (dragging && grab)
            {
               //cerr << "stop drag\n";
               gnome_canvas_item_ungrab(item, event->button.time);
               dragging = FALSE;
               grab=false;
               dynamic_cast<GUINetwork *>(net)->updateScroll();
            } else 
            {
               //cerr << "start drag\n";
               xtmp = item_x;
               ytmp = item_y;
               
               fleur = gdk_cursor_new(GDK_FLEUR);
               gnome_canvas_item_grab(item,
                                      GDK_ENTER_NOTIFY_MASK |
                                      GDK_LEAVE_NOTIFY_MASK |
                                      GDK_FOCUS_CHANGE_MASK |
                                      GDK_POINTER_MOTION_MASK | 
                                      GDK_BUTTON_RELEASE_MASK |
                                      GDK_BUTTON_PRESS_MASK,
                                      //GDK_ALL_EVENTS_MASK,
                                      fleur,
                                      event->button.time);

	       //if not already selected
	       if (!dynamic_cast<GUINetwork *>(net)->isNodeSelected(this)) {

		 //selecting node
		 select();
		 
		 //unselect other nodes
		 dynamic_cast<GUINetwork *>(net)->emptySelectedNodes();
		 
		 //adding this one to the selected list
		 dynamic_cast<GUINetwork *>(net)->addSelectedNode(this);
		 
	       }


               gdk_cursor_destroy(fleur);
               dragging = TRUE;
            }
         }
         return TRUE;
         break;
      case 2:
	 //dynamic_cast<GUINetwork *> (net)->popTooltip(this);
	 
         vflowGUI::instance()->display_treeview_nodetype(getType());
	 return TRUE;
	
         break;

      case 3:
         gnome_popup_menu_do_popup_modal (popupMenu,NULL,NULL,&(event->button),NULL, GTK_WIDGET(dynamic_cast<GUINetwork*>(net)->getCanvas()));
         return TRUE;
         break;
      default:
         break;
      }
      break;

   case GDK_MOTION_NOTIFY:
     
    
     
     if (my_info) {
       vflowGUI::instance()->display_statusbar_text(getName() + getDescription() + string(" : ") + my_info->description);
     }
     else {
       vflowGUI::instance()->display_statusbar_text(getName());
     }

    
      /*if (event->button.state & GDK_SHIFT_MASK)
      {
	 dynamic_cast<GUINetwork *>(net)->popTooltip(this);
      } else {
	 dynamic_cast<GUINetwork *>(net)->popTooltip(NULL);
	 }*/
      if (dragging && (grab || (event->motion.state & GDK_BUTTON1_MASK))) 
      {
         new_x = item_x;
         new_y = item_y;
         move(new_x - xtmp, new_y - ytmp);
         //gnome_canvas_item_move(item, new_x - xtmp, new_y - ytmp);
	
         xtmp = new_x;
         ytmp = new_y;
	 

	 net->setModified();
	 dynamic_cast<GUINetwork*>(net)->auto_scroll(item_x,item_y);
      }

      return TRUE;

      break;
      
   case GDK_ENTER_NOTIFY:     
     dynamic_cast<GUINetwork *>(net)->popTooltip(this);
      break;
   case GDK_LEAVE_NOTIFY:
      dynamic_cast<GUINetwork *>(net)->popTooltip(NULL);
      break;
   case GDK_BUTTON_RELEASE:


      if (!grab)
      {
         //printf ("button release on node\n");
         gnome_canvas_item_ungrab(item, event->button.time);
         dragging = FALSE;
         dynamic_cast<GUINetwork *> (net)->updateScroll();
      }
      break;
   case GDK_2BUTTON_PRESS:
      //cerr << "double-click\n";
      //dynamic_cast<GUINodeParameters *> (parameters)->show();
      propertiesShow();
      break;
   default:
      break;
   }
  
   return FALSE;
}

void GUINode::move(double dx, double dy)
{
  GUINetwork *my_net = dynamic_cast<GUINetwork *>(net);

  if (my_net->isNodeSelected(this)) {
    my_net->moveSelectedNodes(dx,dy);
  }
  else {
    int i;

    setPos(x + dx, y + dy);
    gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), dx, dy);
    for (i=0;i<inputs.size();i++)
      dynamic_cast<GUITerminal *>(inputs[i])->move(dx, dy);
    for (i=0;i<outputs.size();i++)
      dynamic_cast<GUITerminal *>(outputs[i])->move(dx, dy);
  }
}

void GUINode::selectedMove(double dx,double dy) {
  int i;
  setPos(x + dx, y + dy);
  gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), dx, dy);
  for (i=0;i<inputs.size();i++)
    dynamic_cast<GUITerminal *>(inputs[i])->move(dx, dy);
  for (i=0;i<outputs.size();i++)
    dynamic_cast<GUITerminal *>(outputs[i])->move(dx, dy);
}



UILink *GUINode::newLink (UITerminal *_from, UITerminal *_to)
{
   return new GUILink (_from, _to);
}

UINetTerminal *GUINode::newNetTerminal (UITerminal *_terminal, UINetTerminal::NetTermType _type, const string &_name,
					  const string &_objType, const string &_description) {

  return new GUINetTerminal (_terminal, _type, _name, _objType, _description);
}

void GUINode::addTerminal(const string &_name, UINetTerminal::NetTermType _type,
			  const string &_objType, const string &_description) {

  double x1=0,y1=0,x2=0,y2=0;
  
  gnome_canvas_item_get_bounds(nodeRect, &x1,&y1,&x2,&y2);
  

  ItemInfo info;

  info.name = _name;
  info.type = _objType;
  info.description = _description;

 
  switch (_type) {

  case UINetTerminal::INPUT :

    inputs.insert(inputs.end(), new GUITerminal (&info, this, true, x1, y1));
    
    break;

  case UINetTerminal::OUTPUT:

    outputs.insert(outputs.end(), new GUITerminal (&info, this, false, x2,y2 ));
    
    break;

  default:
    break;

  }

  redraw();
  

}

void GUINode::initialize_widgets() {
     
  double x1,y1,x2,y2;
  GnomeCanvasItem *item1,*item2;

  //getting the group
  GnomeCanvasGroup* netGroup = dynamic_cast<GUINetwork *> (net)->getGroup();


  //creating the group
  group = GNOME_CANVAS_GROUP (gnome_canvas_item_new (netGroup,
						     gnome_canvas_group_get_type(),
						     "x", x,
						     "y", y,
						     NULL));

  //creating the node name
  nodeText = gnome_canvas_item_new(group,
				gnome_canvas_text_get_type(),
				"x", 0.0,
				"y", 0.0,
				"text", type.c_str(),
				"anchor", GTK_ANCHOR_CENTER,
				"fill_color", "black",
				"font", "sans 10",
				NULL);



  //getting the node bounds
  gnome_canvas_item_get_bounds(nodeText, &x1,&y1, &x2, &y2);      
  gnome_canvas_item_raise_to_top(nodeText);


  
  vector<ItemInfo *> inputname = net->getDocument()->getNetInputs(type);
  vector<ItemInfo *> outputname = net->getDocument()->getNetOutputs(type);
  

  //creating input items
  for (int i=0;i<inputname.size();i++) {
    //cout<<"insert input"<<endl;
    inputs.insert(inputs.end(), new GUITerminal (inputname[i], this, true, x1,y1));
  }

  //creating output items
  for (int i=0;i<outputname.size();i++) {
    //cout<<"insert output"<<endl;
    outputs.insert(outputs.end(), new GUITerminal (outputname[i], this, false, x2, y2));
  }

  //creating node XPM representation
  if (Node::getXPM(getType()) != NULL) {
  
    GdkPixbuf *pixbuf;
    GnomeCanvasItem *pixbuf_item;
    
    pixbuf = gdk_pixbuf_new_from_xpm_data ((const char**)Node::getXPM(getType()));

    g_assert (pixbuf != NULL);
    
    pixbuf_item = gnome_canvas_item_new (group,
					 gnome_canvas_pixbuf_get_type(),
					 "pixbuf", pixbuf,
					 "anchor", GTK_ANCHOR_CENTER,
					 NULL);
    
    gnome_canvas_item_lower_to_bottom(pixbuf_item);

    gdk_pixbuf_unref (pixbuf);
  }

   guint32 col = FlowPref::getColor("VFLOW", "RegularColor");
 
  //creating rectangle
  nodeRect = gnome_canvas_item_new(group,
				gnome_canvas_rect_get_type(),
				"x1", x1-5,
				"y1", y1-5,
				"x2", x2+5,
				"y2", y2+5,
				"fill_color_rgba", col,
				"outline_color", "black",
				"width_units", 2.0,
				NULL);

  gnome_canvas_item_lower_to_bottom(nodeRect);

  //adding node label (under)
  nodeLabel = gnome_canvas_item_new(group,
				    gnome_canvas_text_get_type(),
				    "x", 0.0,
				    "y", y2 + 10.0,
				    "text",name.c_str(),
				    "anchor", GTK_ANCHOR_CENTER,
				    "fill_color", "black",
				    "font", "sans 8",
				    NULL);

  gnome_canvas_item_raise_to_top(nodeLabel);

  
  


  gtk_signal_connect(GTK_OBJECT(group), "event",
		     (GtkSignalFunc) node_handler,
		     this);

  //updating boundaries
  redraw();

}


void GUINode::redraw() {
  
  double tx1,ty1,tx2,ty2;
  double rx1,ry1,rx2,ry2;
  double max_inputs = 5;
  double max_outputs = 5;
  double start_y1;
  double start_y2;

  int inSize = inputs.size();
  int outSize = outputs.size();

  //the node Text is the reference
  gnome_canvas_item_get_bounds (nodeText,&tx1,&ty1,&tx2,&ty2);

  //rectangle bounding box
  rx1 = tx1;
  ry1 = ty1;
  rx2 = tx2;
  ry2 = ty2;

  //centering on label
  start_y1 = (ty1 + ty2) / 2.0 - max(0.0,inSize  - 1.0) * 15.0 / 2.0;
  start_y2 = (ty1 + ty2) / 2.0 - max(0.0,outSize - 1.0) * 15.0 / 2.0;


  //finding max size for text + input terminal

  if (inSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) {
    for (int i = 0; i < inSize; i++) {
      max_inputs = max(max_inputs,dynamic_cast<GUITerminal*>(inputs[i])->getWidth() + 10.0);    
    }
  }

  
  //finding max size for text + output terminal
  if (outSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) {
    for (int i = 0; i < outSize; i++) {
      max_outputs = max(max_outputs,dynamic_cast<GUITerminal*>(outputs[i])->getWidth() + 10.0);
    }
  }


  //let's position the inputs
  for (int i = 0; i < inSize; i++) { 

    if (inSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) {
      dynamic_cast<GUITerminal*>(inputs[i])->showName();
    }
    else {
      dynamic_cast<GUITerminal*>(inputs[i])->hideName();
    }
  
    //position text & terminal
    dynamic_cast<GUITerminal*>(inputs[i])->setAbsPos(tx1 - max_inputs, start_y1 + 15 * (i));

    //reposition netTerminal
    if (inputs[i]->getNetTerminal()) {
      //TODO reposition net terminal
      //DL 1 Feb 2002
      dynamic_cast<GUINetTerminal*>(inputs[i]->getNetTerminal())->setAbsPos(tx1 - max_outputs - 10, start_y1 + 15 * (i));
    }

  }//inputs


  //let's find the maximum width of the output
  for (int i = 0; i < outSize; i++) {

    if (outSize > 1 || FlowPref::getBool("VFLOW", "ShowAllInOut")) {
      dynamic_cast<GUITerminal*>(outputs[i])->showName();
    }
    else {
      dynamic_cast<GUITerminal*>(outputs[i])->hideName();
    }
    //position text & terminal
    dynamic_cast<GUITerminal*>(outputs[i])->setAbsPos(tx2 + max_outputs, start_y2 + 15 * (i));

    //reposition netTerminal
    if (outputs[i]->getNetTerminal()) {
      //TODO reposition net terminal
      //DL 1 Feb 2002
      dynamic_cast<GUINetTerminal*>(outputs[i]->getNetTerminal())->setAbsPos(tx2 + max_outputs + 10, start_y2 + 15 * (i));
    }



  }//outputs



  rx1 -= max_inputs; 
  rx2 += max_outputs;

  //dont forget text size
  ry1 = min(start_y1,start_y2) - 10;
  ry2 = min(start_y1,start_y2) + 15.0 * max(0,max(inSize -1,outSize -1)) + 10;

  //updating rectangle
  gnome_canvas_item_set(nodeRect,
			"x1",rx1,
			"y1",ry1,
			"x2",rx2,
			"y2",ry2,
			NULL);

  //updating node label
  gnome_canvas_item_set(nodeLabel,
			"x",(rx1 + rx2) / 2.0,
			"y",ry2 + 10.0,
			NULL);
			


}

void GUINode::notifyError(const string &message)
{
   guint32 col = FlowPref::getColor("VFLOW", "ErrorColor");
   gnome_canvas_item_set (nodeRect,
			  "fill_color_rgba", col,
			  NULL);
   //cerr << "color" << endl;
   //dynamic_cast<GUINetwork *> (getNetwork())->updateScroll();
}

void GUINode::select() {

   guint32 col = FlowPref::getColor("VFLOW", "SelectedColor");
   gnome_canvas_item_set (nodeRect,
			  "fill_color_rgba", col,
			  NULL);
}

void GUINode::unselect() {
   guint32 col = FlowPref::getColor("VFLOW", "RegularColor");
   gnome_canvas_item_set (nodeRect,
			  "fill_color_rgba", col,
			  NULL);
}

void GUINode::getBounds(double &x1, double &y1, double &x2, double &y2) 
{

   //getting bounds of the group
   gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM(group),
                                 &x1,
                                 &y1,
                                 &x2,
                                 &y2);


}

void GUINode::rename(const string &newName) {

  UINode::rename(newName);

  //change the type text

  
  gnome_canvas_item_set(nodeText,"text",type.c_str(),NULL);
                             

  redraw();

}

UINodeParameters *GUINode::newNodeParameters (UINode *_node, string type) {
  return new GUINodeParameters (_node, type);
}
}//namespace FD


syntax highlighted by Code2HTML, v. 0.9.1