/* -*- Mode: C -*-
 * $Id: gxsnmp_mib_browser.c,v 1.5 2000/02/20 16:44:41 jochen Exp $
 * GXSNMP - An snmp managment application
 * Copyright (C) 1998 Gregory McLean
 *
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
 *
 * The mib browser panel.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gnome.h>
#include <smi.h>

#include "gxsnmp_mib_browser.h"
#include "gxsnmp_table_dialog.h"
#include "gxsnmp_util.h"
//#include "gxsnmp_request.h"

#include "debug.h"

/****************************************************************************
 * Static data
 ***************************************************************************/
#define BROWSER_LABELS 6
static gchar *browser_labels[] = {
  N_("Object Type"), N_("Module"), N_("OID"), N_("Status"), N_("Label"), 
  N_("Value")
};

static const value_string smi_basetype[] = {
  { SMI_BASETYPE_INTEGER32, 		N_("Integer32")},
  { SMI_BASETYPE_OCTETSTRING, 		N_("String")},
  { SMI_BASETYPE_OBJECTIDENTIFIER,	N_("Object ID")},
  { SMI_BASETYPE_UNSIGNED32,		N_("Unsigned32")},
  { SMI_BASETYPE_INTEGER64, 		N_("Integer64")},
  { SMI_BASETYPE_UNSIGNED64,		N_("Unsigned64")},
  { SMI_BASETYPE_FLOAT32,		N_("Float32")},
  { SMI_BASETYPE_FLOAT64,		N_("Float64")},
  { SMI_BASETYPE_FLOAT128,		N_("Float128")},
  { SMI_BASETYPE_ENUM,			N_("Enum")},
  { SMI_BASETYPE_BITS,			N_("Bits")},
  { SMI_BASETYPE_UNKNOWN,		N_("Unknown")},
  { 0, NULL}};

static const value_string smi_status[] = {
  { SMI_STATUS_CURRENT, 		N_("Current")},
  { SMI_STATUS_DEPRECATED, 		N_("Deprecated")},
  { SMI_STATUS_MANDATORY, 		N_("Mandatory")},
  { SMI_STATUS_OPTIONAL, 		N_("Optional")},
  { SMI_STATUS_OBSOLETE, 		N_("Obsolete")},
  { SMI_STATUS_UNKNOWN, 		N_("Unknown")},
  { 0, NULL}};

static const value_string smi_node_pixmap[] = {
  { SMI_NODEKIND_NODE,			"gxsnmp/node_node.xpm"},
  { SMI_NODEKIND_SCALAR,		"gxsnmp/node_scalar.xpm"},
  { SMI_NODEKIND_TABLE,			"gxsnmp/node_table.xpm"},
  { SMI_NODEKIND_ROW,			"gxsnmp/node_row.xpm"},
  { SMI_NODEKIND_COLUMN,		"gxsnmp/node_column.xpm"},
  { SMI_NODEKIND_NOTIFICATION,		"gxsnmp/node_notification.xpm"},
  { SMI_NODEKIND_GROUP,			"gxsnmp/node_group.xpm"},
  { SMI_NODEKIND_COMPLIANCE,		"gxsnmp/node_compliance.xpm"},
  { SMI_NODEKIND_UNKNOWN,		"gxsnmp/node_unknown.xpm"},
  { 0, NULL}};

enum
{
  TARGET_OID,
  TARGET_STRING
};

static const GtkTargetEntry drag_targets[] = {
  { "application/x-gxsnmp-oid", 0, TARGET_OID },
  { "text/plain", 0, TARGET_STRING }
};

/****************************************************************************
 * Local Struct
 ***************************************************************************/
struct gxsnmp_node_data {
  char *module;
  char *name;
};

/****************************************************************************
 * Forward declarations and callback functions  
 ***************************************************************************/
static void      browser_class_init       (GxSNMPMibBrowserClass     *klass);
static void      browser_init             (GxSNMPMibBrowser          *dialog);
static gint      browser_close_cb         (GxSNMPMibBrowser          *dialog,
					   gpointer                   data);
static void      browser_dialog_cb        (GxSNMPMibBrowser          *dialog,
					   gint                       button,
                                           gpointer                   data);
static void      build_mib_tree           (GxSNMPMibBrowser          *dialog);
static void      cb_select_row            (GtkCTree                  *ctree,
					   gint			      row,
					   gint			      col,
					   GdkEvent		     *e,
                                           gpointer                   data);
static void	 mib_tree_drag_begin	  (GtkWidget		     *widget,
					   GdkDragContext	     *context,
					   gpointer		      data);
static void	 mib_tree_data_get	  (GtkWidget		     *widget,
					   GdkDragContext	     *context,
					   GtkSelectionData	     *sel_data,
					   guint		      info,
					   guint		      dtime,
					   gpointer		      data);
static void	 cb_node_destroy	  (gpointer		      data);
static void	 walk_button_cb		  (GtkWidget		     *widget,
					   gpointer		      data);
static void	 table_button_cb	  (GtkWidget		     *widget,
					   gpointer		      data);
static void	 get_button_cb		  (GtkWidget		     *widget,
					   gpointer		      data);
static void	 put_button_cb		  (GtkWidget		     *widget,
					   gpointer		      data);
/****************************************************************************
 * Class registration
 ***************************************************************************/
/**
 * gxsnmp_mib_browser_get_type:
 *
 * Registers class with GTK and returns handle ("type") of class. The handle
 * is cached in a static class variable for repeated calls of this function.
 *
 * Return value: unique type
 **/
GtkType
gxsnmp_mib_browser_get_type ()
{
  static GtkType list_type = 0;
  D_FUNC_START;
  if (!list_type)
    {
      GtkTypeInfo list_info = 
      {
	"GxSNMPMibBrowser",
	sizeof (GxSNMPMibBrowser),
	sizeof (GxSNMPMibBrowserClass),
	(GtkClassInitFunc) browser_class_init,
	(GtkObjectInitFunc) browser_init,
	/* reserved 1 */ NULL,
	/* reserved 2 */ NULL,
	(GtkClassInitFunc) NULL,
      };
      list_type =gtk_type_unique(gnome_dialog_get_type(), &list_info);
    }
  D_FUNC_END;
  return list_type;
}
/****************************************************************************
 * Static Helper functions
 ***************************************************************************/
/**
 * getoid:
 * @node: SMI node whose OID should be formatted
 * @buffer: result buffer
 * @buflen: length of buffer
 *
 * Formats an OID of a node into a preallocated buffer.
 *
 **/
static void
getoid (SmiNode *node, char *buffer, int buflen)
{
  int i;
  D_FUNC_START;
  snprintf(buffer, buflen, "%d", node->oid[0]);
  for (i=1; i < node->oidlen; i++)
    snprintf(buffer + strlen (buffer), buflen - strlen (buffer), ".%d", 
             node->oid[i]);
  D_FUNC_END;
}
/**
 * cb_node_destroy:
 * @data: pointer to data 
 *
 * Frees data of node information
 *
 **/
static void
cb_node_destroy (gpointer data)
{
  g_free(data);
}
/****************************************************************************
 * Class methods
 ***************************************************************************/
/**
 * browser_class_init:
 * @klass: self 
 *
 * Constructor of this class.
 *
 **/
static void
browser_class_init (GxSNMPMibBrowserClass *klass)
{
  D_FUNC_START;
  D_FUNC_END;
}
/****************************************************************************
 * Object methods
 ***************************************************************************/
/**
 * browser_init:
 * @dialog: self 
 *
 * Constructor of this object.
 *
 * Constructs all "HAVING" GUI objects except for MIB tree. The root node of
 * the MIB tree is created here, but the rest will be created in 
 * build_mib_tree(). [Does this still make sense? - jochen]
 *
 **/
static void
browser_init (GxSNMPMibBrowser *dialog)
{
  GtkWidget    *hbox;
  GtkWidget    *vbox;
  GtkWidget    *table;
  GtkWidget    *frame;
  GtkWidget    *label;
  GtkWidget    *hscroll;
  GtkWidget    *vscroll;
  GtkWidget    *bar;
  GtkWidget    *button_box;
  GtkWidget    *scrolled_window;
  int           i;

  D_FUNC_START;
  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(dialog)->vbox), 
                      hbox, TRUE, TRUE, 0);
/* Left side shows MIB tree */
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
  gtk_widget_set_usize (GTK_WIDGET (scrolled_window), 250, 250);
  dialog->root = gtk_ctree_new (1, 0);
  gtk_clist_set_selection_mode (GTK_CLIST (dialog->root), GTK_SELECTION_SINGLE);
  gtk_clist_set_column_auto_resize (GTK_CLIST (dialog->root), 0, TRUE);
  gtk_ctree_set_show_stub (GTK_CTREE (dialog->root), FALSE);
  gtk_ctree_set_indent (GTK_CTREE (dialog->root), 10);
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->root), FALSE);
  gtk_drag_source_set (GTK_WIDGET (dialog->root), GDK_BUTTON1_MASK,
                       drag_targets, ELEMENTS (drag_targets), GDK_ACTION_COPY);
  gtk_signal_connect (GTK_OBJECT (dialog->root), "drag_begin",
                     (GtkSignalFunc) mib_tree_drag_begin, dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->root), "drag_data_get",
                     (GtkSignalFunc) mib_tree_data_get, dialog);
  gtk_scrolled_window_add_with_viewport 
                        (GTK_SCROLLED_WINDOW (scrolled_window), dialog->root);
/* Right side shows entry fields */
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 2);
  frame = gtk_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  table = gtk_table_new ( 2, 7, FALSE);
  gtk_container_add (GTK_CONTAINER (frame), table);
/* Create labels */
  for (i=0; i<BROWSER_LABELS; i++)
    { 
      label = gtk_label_new (gettext(browser_labels[i]));
      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
      gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1,
		        GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
    }
/* Create SNMP updatable fields */
  dialog->mib_type = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_type), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_type,
		    1, 2, 0, 1,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_module = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_module), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_module,
		    1, 2, 1, 2,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_oid = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_oid), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_oid, 
		    1, 2, 2, 3,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_status = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_status), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_status, 
		    1, 2, 3, 4,
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_label = gtk_entry_new ();
  gtk_entry_set_editable (GTK_ENTRY (dialog->mib_label), FALSE);
  gtk_table_attach (GTK_TABLE (table), dialog->mib_label,
		    1, 2, 4, 5, 
		    GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
  dialog->mib_value = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), dialog->mib_value,
		    1, 2, 5, 6,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
/* Text entry field for displaying description */
  label = gtk_label_new (_("Description"));
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.1);
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
  dialog->mib_desc = gtk_text_new (NULL, NULL);
  gtk_text_set_editable (GTK_TEXT (dialog->mib_desc), FALSE);
  gtk_widget_set_usize (GTK_WIDGET (dialog->mib_desc), 350, 200);
  GTK_TEXT(dialog->mib_desc)->line_wrap = FALSE;
  gtk_table_attach_defaults (GTK_TABLE (table), dialog->mib_desc, 0, 1, 0, 1);
  hscroll = gtk_hscrollbar_new (GTK_TEXT (dialog->mib_desc)->hadj);
  gtk_table_attach (GTK_TABLE (table), hscroll, 0, 1, 1, 2,
		    GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
  vscroll = gtk_vscrollbar_new (GTK_TEXT (dialog->mib_desc)->vadj);
  gtk_table_attach (GTK_TABLE (table), vscroll, 1, 2, 0, 1,
		    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
/* Buttons for FIRST, NEXT, GET, PUT */
  bar = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (vbox), bar, FALSE, FALSE, 0);
  frame = gtk_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  button_box = gtk_hbutton_box_new ();
  gtk_container_border_width (GTK_CONTAINER (button_box), 2);
  gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box), 
			     GTK_BUTTONBOX_SPREAD);
  gtk_button_box_set_spacing (GTK_BUTTON_BOX (button_box), 2);
  gtk_button_box_set_child_size (GTK_BUTTON_BOX (button_box), 85, 20);
  gtk_container_add (GTK_CONTAINER (frame), button_box);
  dialog->wbutton = gtk_button_new_with_label (_("Walk"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->wbutton);
  dialog->tbutton = gtk_button_new_with_label (_("Table"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->tbutton);
  gtk_widget_set_sensitive (dialog->tbutton, FALSE);
  dialog->gbutton = gtk_button_new_with_label (_("Get"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->gbutton);
  gtk_widget_set_sensitive (dialog->gbutton, FALSE);
  dialog->pbutton = gtk_button_new_with_label (_("Put"));
  gtk_container_add (GTK_CONTAINER (button_box), dialog->pbutton);
  gtk_widget_set_sensitive (dialog->pbutton, FALSE);
/* Connect Signals */
  gtk_signal_connect (GTK_OBJECT (dialog->wbutton), "clicked",
		      GTK_SIGNAL_FUNC (walk_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->tbutton), "clicked",
		      GTK_SIGNAL_FUNC (table_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->gbutton), "clicked",
		      GTK_SIGNAL_FUNC (get_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->pbutton), "clicked",
		      GTK_SIGNAL_FUNC (put_button_cb),
		      dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->root), "select_row",
                      GTK_SIGNAL_FUNC (cb_select_row),
                      dialog);
  gtk_widget_show_all (hbox);
  /* Append buttons for close and help */
  gnome_dialog_append_buttons (GNOME_DIALOG (dialog),
                               GNOME_STOCK_BUTTON_CLOSE,
                               GNOME_STOCK_BUTTON_HELP,
                               NULL);
  gtk_signal_connect (GTK_OBJECT(dialog), "clicked",
		      GTK_SIGNAL_FUNC(browser_dialog_cb), NULL);
  D_FUNC_END;
}
/**
 * get_enums:
 * @dialog: self
 * @node: SMI node to get the enums from
 *
 * Gets the enums of a given SMI node and inserts them into the description
 * field of this dialog.
 *
 **/
static void
get_enums (GxSNMPMibBrowser *dialog, SmiNode *node)
{
  char               buf[80];
  SmiNamedNumber    *num;
  SmiType           *type;
  D_FUNC_START;
  type = smiGetNodeType(node);
  if (type && type->basetype == SMI_BASETYPE_ENUM)
    {
      sprintf (buf, _("\n\nAvailable values:\n\n"));
      gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL,
		       &(dialog->mib_desc)->style->black,
		       NULL, buf, strlen(buf));
      num = smiGetFirstNamedNumber(type);
      while (num)
	{
	  sprintf (buf, "%s (%d)\n", num->name, 
                   (int) num->value.value.integer32);
	  gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL,
			   &(dialog->mib_desc)->style->black,
			   NULL, buf, -1);
	  num = smiGetNextNamedNumber(num);
	}
    }
  D_FUNC_END;
}
/**
 * create_tree_item:
 * @dialog: self
 * @ctree: ctree object
 * @parent: parent tree item
 * @node: SMI node to create tree item for
 *
 * Creates the subtree of the given node and attach it to the parent.
 *
 **/
static void 
create_tree_item(GtkWidget* dialog, GtkCTree* ctree, GtkCTreeNode* parent, 
		 SmiNode *node) 
{
  char buffer[255];
  char *buf[1];
  char *pbuffer;
  GtkCTreeNode *item;
  GnomePixmap *pixmap;
  SmiNode *child;
  SmiModule *module;
  struct gxsnmp_node_data *data;
  D_FUNC_START;
  gtk_main_iteration_do(FALSE); /* keep the UI from locking up */
  if (node->name)
    sprintf(buffer,"%s (%d)", node->name, node->oid[node->oidlen-1]);
  else
    sprintf(buffer,"(%d)", node->oid[node->oidlen-1]);
  pbuffer = match_strval (node->nodekind, smi_node_pixmap);
  if (!pbuffer)
    {
      g_warning("Unknown nodekind found: %d", node->nodekind);
      pbuffer = "gxsnmp/node_unknown.xpm";
    }
  pixmap = GNOME_PIXMAP(gnome_stock_pixmap_widget(dialog, pbuffer));
  buf[0] = buffer;
  item = gtk_ctree_insert_node (ctree, parent, NULL, buf, 1,
				pixmap->pixmap, pixmap->mask, 
				pixmap->pixmap, pixmap->mask,
				FALSE, FALSE);
  data = g_new(struct gxsnmp_node_data, 1);
  module = smiGetNodeModule(node);
  data->name   = node->name;
  data->module = module->name;
  gtk_ctree_node_set_row_data_full(ctree, item, data, cb_node_destroy);
  if ((child = smiGetFirstChildNode(node)))
    {
      while(child)
        {  
          create_tree_item(dialog, ctree, item, child);
          child = smiGetNextChildNode(child);
        }
    }
  D_FUNC_END;
}
/**
 * build_mib_tree:
 * @dialog: self
 *
 * Creates the MIB tree
 *
 **/
static void
build_mib_tree (GxSNMPMibBrowser *dialog)
{
  SmiNode             *node;
  D_FUNC_START;
  if((node = smiGetNode(NULL, "ccitt")))
    {
      create_tree_item (GTK_WIDGET (dialog), GTK_CTREE (dialog->root), 
			NULL, node);
    }
  if((node = smiGetNode(NULL, "iso")))
    {
      create_tree_item (GTK_WIDGET (dialog), GTK_CTREE (dialog->root), 
			NULL, node);
    }
  if((node = smiGetNode(NULL, "joint-iso-ccitt")))
    {
      create_tree_item (GTK_WIDGET (dialog), GTK_CTREE (dialog->root), 
			NULL, node);
    }
  gtk_widget_set_sensitive (GTK_WIDGET (dialog->root), TRUE);
  D_FUNC_END;
}
/****************************************************************************
 * Object signals
 ***************************************************************************/
/**
 * browser_close_cb:
 * @dialog: self
 * @data: unused pointer
 *
 * SIGNAL Method to announce the destruction of this object.
 * The object can veto the destruction by returning a TRUE.
 *
 * Return value: veto
 * 
 **/
static gint
browser_close_cb (GxSNMPMibBrowser *dialog, gpointer data)
{
  D_FUNC_START;
  D_FUNC_END;
  return FALSE;
}
/**
 * browser_dialog_cb:
 * @dialog: self
 * @button: number of button pressed
 * @data: unused pointer
 *
 * SIGNAL Method to handle button presses in the lower dialog area.
 * Button numbers are:
 * 0: CLOSE button
 * 1: HELP button
 *
 **/
static void
browser_dialog_cb (GxSNMPMibBrowser *dialog, gint button, gpointer data)
{
  gchar *tmp;
  D_FUNC_START;
  switch(button)
    {
      case 0:
	gnome_dialog_close (GNOME_DIALOG (dialog));
	break;
      case 1:
	tmp = gnome_help_file_find_file ("gxsnmp", "browser-help.html");
	if (tmp)
	  {
	    gnome_help_goto (0, tmp);
	    g_free (tmp);
	  }
	break;
      default:
	g_assert_not_reached ();
    }
  D_FUNC_END;
}
/****************************************************************************
 * Signals of other objects
 ***************************************************************************/
/**
 * mib_tree_drag_begin:
 * @wigdet: self
 * @context: drag context
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce the begin of a drag operation.
 * 
 * The current focus of the MIB tree is saved in an instance variable of the
 * dialog for a later drop operation.
 *
 **/
static void
mib_tree_drag_begin(GtkWidget* widget, GdkDragContext* context, gpointer data)
{
  GxSNMPMibBrowser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GxSNMPMibBrowser *) data;
  dialog->dragged_row = GTK_CLIST (dialog->root)->focus_row;
  D_FUNC_END;
}
/**
 * mib_tree_data_get:
 * @wigdet: self
 * @context: drag context
 * @sel_data: target of DnD operation
 * @info: data format of DnD operarion
 * @dtime:
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce the begin of a drag operation.
 * 
 * The current focus of the MIB tree is saved in an instance variable of the
 * dialog for a later drop operation.
 *
 **/
static void
mib_tree_data_get(GtkWidget* widget, GdkDragContext* context,
		  GtkSelectionData* sel_data, guint info, guint dtime,
	 	  gpointer data)
{
  GxSNMPMibBrowser *dialog;
  SmiNode          *node;
  SmiModule        *module;
  gchar            *buffer;
  struct gxsnmp_node_data *ndata;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GxSNMPMibBrowser *) data;
  ndata = gtk_clist_get_row_data (GTK_CLIST (dialog->root), 
				  dialog->dragged_row);
  module = smiGetModule(ndata->module);
  node = smiGetNode(module, ndata->name);
  switch (info)
    {
     case TARGET_STRING:
	buffer = (gchar *) g_malloc(1024);
	getoid(node, buffer, 1024);
	gtk_selection_data_set (sel_data, sel_data->target, 8, buffer,
				strlen(buffer));
	g_free(buffer);
	break;
      default:
	buffer = (gchar *) g_malloc(1024);
	snprintf(buffer, 1024, "%s.%s", module->name, node->name);
	gtk_selection_data_set (sel_data, sel_data->target, 8, buffer,
				strlen(buffer));
	g_free(buffer);
    }
  D_FUNC_END;
}
/**
 * cb_select_row:
 * @ctree: self
 * @row: row where event occurred
 * @col: column where event occurred
 * @e: type of event
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce change of selection in a ctree.
 *
 * The dialog is updated to reflect information of the new selected row.
 * This calls get_enums if necessary.
 *
 **/
static void 
cb_select_row(GtkCTree* ctree, gint row, gint col, GdkEvent *e, gpointer data) 
{
  GList          *selected;
  GtkCTreeNode   *selected_item;
  gint            nb_selected;
  guint           length;
  SmiNode        *node;
  SmiModule      *module;
  SmiType        *type;
  gchar          *buffer;
  struct gxsnmp_node_data *ndata;
  GxSNMPMibBrowser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GxSNMPMibBrowser *) data;
  selected    = GTK_CLIST(ctree)->selection;
  nb_selected = g_list_length(selected);
  if (nb_selected != 1) 
    return;
  selected_item = GTK_CTREE_NODE(selected->data);
  ndata = gtk_ctree_node_get_row_data(ctree, selected_item);
  module = smiGetModule(ndata->module);
  node = smiGetNode(module, ndata->name);
  gtk_text_set_point(GTK_TEXT (dialog->mib_desc),0);
  length = gtk_text_get_length(GTK_TEXT (dialog->mib_desc));
  gtk_text_forward_delete(GTK_TEXT (dialog->mib_desc),length);
  if (node)
    {
      type = smiGetNodeType(node);
      if (!type)
        {
	  buffer = _("None");
	}
      else
        {
          buffer = match_strval (type->basetype, smi_basetype);
          if (!buffer)
	    {
	      g_warning("Unknown basetype found: %d", type->basetype);
	      buffer = _("Illegal");
	    }
	}
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_type), buffer);
      buffer = match_strval (node->status, smi_status);
      if (!buffer)
	{
	  g_warning("Unknown status found: %d", node->status);
	  buffer = _("Illegal");
	}
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_status), buffer);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_module), module->name);
      buffer = (gchar *) g_malloc(1024);
      getoid(node, buffer, 1024);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_oid), buffer);
      g_free(buffer);
      gtk_entry_set_text (GTK_ENTRY (dialog->mib_label), node->name);
      if (node->description) 
	{
	  gtk_text_insert (GTK_TEXT (dialog->mib_desc), NULL, 
			  &(dialog->mib_desc)->style->black, 
			  NULL, node->description, strlen
			  (node->description));
        }
      get_enums (dialog, node);
      d_print (DEBUG_DUMP, "Selected node, kind == %d\n", node->nodekind);
      switch (node->nodekind)
	{
	  case SMI_NODEKIND_TABLE:
	    gtk_widget_set_sensitive (dialog->tbutton, TRUE);
	    gtk_widget_set_sensitive (dialog->gbutton, FALSE);
	    gtk_widget_set_sensitive (dialog->pbutton, FALSE);
	    break;
	  case SMI_NODEKIND_SCALAR:
	    gtk_widget_set_sensitive (dialog->tbutton, FALSE);
	    gtk_widget_set_sensitive (dialog->gbutton, TRUE);
	    gtk_widget_set_sensitive (dialog->pbutton, TRUE);
	    break;
	  default:
	    gtk_widget_set_sensitive (dialog->tbutton, FALSE);
	    gtk_widget_set_sensitive (dialog->gbutton, FALSE);
	    gtk_widget_set_sensitive (dialog->pbutton, FALSE);
     	    break;
	} 
    }
  gtk_text_thaw (GTK_TEXT (dialog->mib_desc));
  D_FUNC_END;
}
/**
 * walk_button_cb:
 * @widget: self
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce press of WALK button
 *
 **/
static void
walk_button_cb (GtkWidget* widget, gpointer data)
{
  D_FUNC_START;
  D_FUNC_END;
}
/**
 * table_button_cb:
 * @widget: self
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce press of TABLE button
 *
 **/
static void
table_button_cb	(GtkWidget* widget, gpointer data)
{
  GList          *selected;
  GtkCTreeNode   *selected_item;
  gint            nb_selected;
  SmiNode        *node;
  SmiModule      *module;
  GtkWidget      *table;
  struct gxsnmp_node_data *ndata;
  GxSNMPMibBrowser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GxSNMPMibBrowser *) data;
  selected    = GTK_CLIST(dialog->root)->selection;
  nb_selected = g_list_length(selected);
  if (nb_selected != 1) 
    return;
  selected_item = GTK_CTREE_NODE(selected->data);
  ndata = gtk_ctree_node_get_row_data(GTK_CTREE(dialog->root), selected_item);
  module = smiGetModule(ndata->module);
  node = smiGetNode(module, ndata->name);
  table = gxsnmp_table_dialog_new_from_node(node);
  gtk_widget_show(table);
  D_FUNC_END;
}
/**
 * get_button_cb:
 * @widget: self
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce press of GET button
 *
 **/
static void
get_button_cb (GtkWidget* widget, gpointer data)
{
  GList          *selected;
  GtkCTreeNode   *selected_item;
  gint            nb_selected;
  SmiNode        *node;
  SmiModule      *module;
  struct gxsnmp_node_data *ndata;
  GxSNMPMibBrowser *dialog;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog = (GxSNMPMibBrowser *) data;
  selected    = GTK_CLIST(dialog->root)->selection;
  nb_selected = g_list_length(selected);
  if (nb_selected != 1) 
    return;
  selected_item = GTK_CTREE_NODE(selected->data);
  ndata = gtk_ctree_node_get_row_data(GTK_CTREE(dialog->root), selected_item);
  module = smiGetModule(ndata->module);
  node = smiGetNode(module, ndata->name);
//  if (dialog->request)
//    gtk_object_destroy(dialog->request);
//  dialog->request = gxsnmp_request_new("127.0.0.1", NULL, AF_INET, "public", 
//					10, 10, result_cb, error_cb, dialog);
//  instance = 0;
//  gxsnmp_request_add_oid(dialog->request, node->oid, node->oidlen, 
//                         &instance, 1, SNMP_NULL, NULL);
//  gxsnmp_request_execute(dialog->request);
  D_FUNC_END;
}
/**
 * put_button_cb:
 * @widget: self
 * @data: pointer to dialog object
 *
 * SIGNAL Method to announce press of PUT button
 *
 **/
static void
put_button_cb (GtkWidget* widget, gpointer data)
{
  D_FUNC_START;
  D_FUNC_END;
}
/****************************************************************************
 * Public API
 ***************************************************************************/
/**
 * gxsnmp_mib_browser_new:
 *
 * Creates new MIB browser object
 *
 * Return value: MIB browser object
 **/
GtkWidget *
gxsnmp_mib_browser_new ()
{
  GxSNMPMibBrowser  *dialog;
  D_FUNC_START;
  dialog = gtk_type_new (gxsnmp_mib_browser_get_type ());
  if (dialog)
    {
      build_mib_tree (dialog);
      gtk_signal_connect (GTK_OBJECT (dialog), "close",
			  GTK_SIGNAL_FUNC (browser_close_cb), NULL);
      D_FUNC_END;
      return GTK_WIDGET (dialog);
    }
  D_FUNC_END;
  return NULL;
}
/* EOF */
