/*
 *  $Id: network_dialog.c,v 1.16 2000/07/23 00:55:29 remlali Exp $
 *
 *  GXSNMP -- An snmp management 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 network_dialog widget is used to enter in and edit network data.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gnome.h>
#include "gnome-property-dialog.h"
#include "network_dialog.h"
#include "main.h"			/* Needed for gxsnmp struct */
#include "dbapi.h"
#include "gxsnmp/gxsnmp_dbapi.h"
#include "graph_panel.h"
#include "panel_utility.h"
#include "gxsnmp_window.h"
#include "gxsnmp_map.h"
#include "gxsnmp_map_item.h"

#include "debug.h"

extern gxsnmp *app_info;

/****************************************************************************
 *
 * Static data
 ***************************************************************************/

#define GRAPH_CLIST_COLUMNS 2
static gchar  *graph_clist_titles[]             = { "Map Name", "Displayed" };
static gint    graph_clist_title_widths[2]	= { 15, 9 };

/****************************************************************************
 * Forward declarations and callback functions
 ***************************************************************************/

static void  network_dialog_class_init    (GXsnmp_network_dialogClass *klass);
static void  network_dialog_init          (GXsnmp_network_dialog      *dialog);
static void  network_dialog_help_cb       (GtkWidget                  *widget,
                                           gpointer                   data);
static void  network_panel_changed_cb     (GtkWidget                  *widget,
					   gpointer                   data);
static void  graph_changed_cb             (GtkWidget                  *widget,
					   gpointer                   data);
static gint  network_close_cb             (GtkWidget                  *widget,
					   gpointer                   data);
static void  network_apply_cb             (GtkWidget                  *widget,
					   gpointer                   data);
static void  network_refresh_cb           (G_sqldb_table              *table,
					   gpointer                   row,
					   G_sqldb_cb_type            type,
					   gpointer                   data);
static void  graph_select_row_cb          (GtkWidget                  *widget,
					   gint                       row,
					   gint                       column,
					   GdkEventButton             *event,
					   gpointer                   data);
static void  graph_show_button_cb         (GtkWidget                  *widget,
					   gpointer                   data);
static void  graph_hide_button_cb         (GtkWidget                  *widget,
					   gpointer                   data);
static void  set_dialog_state             (GXsnmp_network_dialog      *dialog);
/****************************************************************************
 * gxsnmp_network_dialog_get_type()
 ***************************************************************************/
GtkType
gxsnmp_network_dialog_get_type ()
{
  static GtkType gnd_type = 0;
  D_FUNC_START;
  if (!gnd_type)
    {
      GtkTypeInfo gnd_info = 
      {
	"GXsnmp_network_dialog",
	sizeof (GXsnmp_network_dialog),
	sizeof (GXsnmp_network_dialogClass),
	(GtkClassInitFunc) network_dialog_class_init,
	(GtkObjectInitFunc) network_dialog_init,
	/* reserved 1 */ NULL,
	/* reserved 2 */ NULL,
	(GtkClassInitFunc) NULL,
      };
      gnd_type = gtk_type_unique (gnome_property_dialog_get_type(), &gnd_info);
    }
  D_FUNC_END;
  return gnd_type;
}

/****************************************************************************
 * Class initialization subroutine.
 ***************************************************************************/
static void
network_dialog_class_init (GXsnmp_network_dialogClass *class)
{
  d_print (DEBUG_TRACE, "\n");
}

/****************************************************************************
 * Widget initialization subroutine
 ***************************************************************************/
static void
network_dialog_init (GXsnmp_network_dialog *dialog)
{
  GtkWidget    *label;
  GtkWidget    *separator;
  GtkWidget    *button_box;
  GtkWidget    *vbox;
  GtkWidget    *pixmap;
  gint         i, c_width, c_height;
  D_FUNC_START;
  
  dialog->table = gtk_table_new (6, 5, FALSE);
  gtk_table_set_row_spacings (GTK_TABLE (dialog->table), 7);
  gtk_table_set_col_spacings (GTK_TABLE (dialog->table), 7);
  gtk_container_set_border_width (GTK_CONTAINER (dialog->table), 7);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
		      dialog->table, TRUE, TRUE, 0);
  c_width  = gdk_string_width (dialog->table->style->font, "xW") / 2;
  c_height = dialog->table->style->font->ascent + 
             dialog->table->style->font->descent;
  d_print (DEBUG_DUMP, "c_width (%d), c_height (%d)\n", c_width, c_height);
  /*
   * Column one contains the network editing panel. (and a discover button?)
   */
  label = gtk_label_new (_("Network Information"));
  gtk_table_attach (GTK_TABLE (dialog->table), label,
		    0, 1, 0, 1, 0, 0, 0, 0);
  dialog->network_panel = gxsnmp_network_panel_new ();
  gtk_table_attach (GTK_TABLE (dialog->table), dialog->network_panel,
		    0, 1, 1, 2, 0, 0, 0, 0);

  separator = gtk_vseparator_new ();
  gtk_table_attach (GTK_TABLE (dialog->table), separator, 1, 2, 0, 4,
		    0, GTK_EXPAND | GTK_FILL, 0, 0);

  /* 
   * Column two is the display editing panle and display list
   */
  label = gtk_label_new (_("Display Information"));
  gtk_table_attach (GTK_TABLE (dialog->table), label,
		    2, 3, 0, 1, 0, 0, 0, 0);
  vbox = gtk_vbox_new (FALSE, 4);
  gtk_table_attach (GTK_TABLE (dialog->table), vbox,
		    2, 3, 1, 2, 0, 0, 0, 0);
  dialog->graph_panel = gxsnmp_graph_panel_new ();
  gtk_box_pack_start (GTK_BOX (vbox), dialog->graph_panel, TRUE, TRUE, 0);
  dialog->no_graph_panel = gtk_label_new (_("Network not displayed on this map"));
  gtk_box_pack_start (GTK_BOX (vbox), dialog->no_graph_panel, TRUE, TRUE, 0);
  
  dialog->graph_scroll = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dialog->graph_scroll),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
  gtk_table_attach (GTK_TABLE (dialog->table), dialog->graph_scroll,
		    2, 3, 2, 3, 
		    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  dialog->graph_clist = gtk_clist_new_with_titles (GRAPH_CLIST_COLUMNS,
						   graph_clist_titles);
  gtk_clist_set_selection_mode (GTK_CLIST (dialog->graph_clist),
				GTK_SELECTION_BROWSE);
  gtk_clist_column_titles_passive (GTK_CLIST (dialog->graph_clist));
  for (i = 0; i < GRAPH_CLIST_COLUMNS; i++)
    gtk_clist_set_column_width (GTK_CLIST (dialog->graph_clist), i, 
                                c_width * graph_clist_title_widths[i]);
  gtk_container_add (GTK_CONTAINER (dialog->graph_scroll),
		     dialog->graph_clist);
  button_box = gtk_hbutton_box_new ();
  gtk_table_attach (GTK_TABLE (dialog->table), button_box,
		    2, 3, 3, 4, 0, 0, 0, 0);
  pixmap = gnome_stock_pixmap_widget (GTK_WIDGET (dialog),
				      "gxsnmp/add_host.xpm");

  dialog->graph_show_button = gnome_pixmap_button (pixmap, _("Show"));
  gtk_box_pack_start (GTK_BOX (button_box), dialog->graph_show_button,
		      TRUE, TRUE, 0);
  pixmap = gnome_stock_pixmap_widget (GTK_WIDGET (dialog),
				      "gxsnmp/del_host.xpm");
  dialog->graph_hide_button = gnome_pixmap_button (pixmap, _("Hide"));
  gtk_box_pack_start (GTK_BOX (button_box), dialog->graph_hide_button,
		      TRUE, TRUE, 0);
  /* Connect up the signals */
  gtk_signal_connect (GTK_OBJECT (dialog), "apply",
		      GTK_SIGNAL_FUNC (network_apply_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog), "help",
                      GTK_SIGNAL_FUNC (network_dialog_help_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog), "close",
		      GTK_SIGNAL_FUNC (network_close_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->network_panel), "changed",
		      GTK_SIGNAL_FUNC (network_panel_changed_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->graph_panel), "changed",
		      GTK_SIGNAL_FUNC (graph_changed_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->graph_clist), "select_row",
		      GTK_SIGNAL_FUNC (graph_select_row_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->graph_show_button), "clicked",
		      GTK_SIGNAL_FUNC (graph_show_button_cb), dialog);
  gtk_signal_connect (GTK_OBJECT (dialog->graph_hide_button), "clicked",
		      GTK_SIGNAL_FUNC (graph_hide_button_cb), dialog);

  /* And finally show the whole shooting match. */
  gtk_widget_show_all (dialog->table);
  D_FUNC_END;
}
/****************************************************************************
 * Callback handler for the "select_row" signal from the graph clist.
 ***************************************************************************/
static void
graph_select_row_cb (GtkWidget *widget, gint row, gint column,
		     GdkEventButton *event, gpointer data)
{
  GXsnmp_network_dialog   *dialog;
  GtkCList                *clist;
  guint                   *row_data;
  guint                   graph_rowid;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  g_return_if_fail (GXSNMP_IS_NETWORK_DIALOG (data));
  dialog  = GXSNMP_NETWORK_DIALOG (data);
  clist   = GTK_CLIST (widget);
  g_return_if_fail (GTK_IS_CLIST (clist));
  dialog->graph_row = row;
  row_data = gtk_clist_get_row_data (clist, row);
  graph_rowid = row_data[1];
  if (graph_rowid)
    dialog->selected_graph = graph_find_by_rowid (graph_rowid);
  else
    dialog->selected_graph = NULL;
  if (dialog->selected_graph)
    {
      gtk_signal_handler_block_by_data (GTK_OBJECT (dialog->graph_panel),
					dialog);
      gxsnmp_graph_panel_put_data (GXSNMP_GRAPH_PANEL (dialog->graph_panel),
				   dialog->selected_graph);
      gtk_signal_handler_unblock_by_data (GTK_OBJECT (dialog->graph_panel),
					  dialog);
    }
  set_dialog_state (dialog);
  D_FUNC_END;
}
/****************************************************************************
 * Callback handler for the "clicked" signal from the map "show" button
 ***************************************************************************/
static void
graph_show_button_cb (GtkWidget *widget, gpointer data)
{
  GXsnmp_network_dialog  *dialog;
  GtkCList               *clist;
  guint                  *row_data;
  guint                  map_rowid;
  guint                  graph_rowid;
  DB_graph               *dbg;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  g_return_if_fail (GXSNMP_IS_NETWORK_DIALOG (data));
  dialog = GXSNMP_NETWORK_DIALOG (data);
  clist  = GTK_CLIST (dialog->graph_clist);
  row_data    = gtk_clist_get_row_data (clist, dialog->graph_row);
  map_rowid   = row_data[0];
  graph_rowid = row_data[1];
  g_assert (graph_rowid == 0);
  dbg          = graph_create ();
  if (dbg)
    {
      dbg->map     = map_rowid;
      dbg->type    = DB_GRAPH_NETWORK;
      dbg->network = dialog->selected_network->rowid;
      dbg->x       = dialog->x;
      dbg->y       = dialog->y;
      graph_add (dbg);
      dialog->graph_dirty = FALSE;
      network_refresh_cb (network_sqldb, dialog->selected_network,
			  G_SQLDB_CB_UPDATE, dialog);
    }
  else
    {
      g_warning ("Unable to allocate memory for new network graph object.");
    }
  D_FUNC_END;
}
/***************************************************************************
 * Callback handler for the "clicked" signal from the map "hide" button
 ***************************************************************************/

static void
graph_hide_button_cb (GtkWidget *widget, gpointer data)
{
  GXsnmp_network_dialog *dialog;
  GtkCList              *clist;
  guint                 *row_data;
  guint                 graph_rowid;
  DB_graph              *dbg;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  g_return_if_fail (GXSNMP_IS_NETWORK_DIALOG (data));
  dialog = GXSNMP_NETWORK_DIALOG (data);
  clist  = GTK_CLIST (dialog->graph_clist);

  row_data = gtk_clist_get_row_data (clist, dialog->graph_row);
  graph_rowid = row_data[1];
  g_assert (graph_rowid != 0);
  
  dbg = graph_find_by_rowid (graph_rowid);
  graph_delete (dbg);
  graph_destroy (dbg);
  dialog->selected_graph = NULL;
  dialog->graph_dirty = FALSE;
  network_refresh_cb (network_sqldb, dialog->selected_network,
		      G_SQLDB_CB_UPDATE, dialog);
  D_FUNC_END;
}

/****************************************************************************
 * Callback handler for the apply signal from the gnome_property_dialog
 ***************************************************************************/
static void
network_apply_cb (GtkWidget *widget, gpointer data)
{
  GXsnmp_network_dialog   *dialog;
  DB_network              *dbn;
  DB_graph                *dbg;
  gboolean                changed;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  g_return_if_fail (GXSNMP_IS_NETWORK_DIALOG (data));
  dialog = GXSNMP_NETWORK_DIALOG (widget);
  dbn = dialog->selected_network;
  if (dbn)
    {
      changed = gxsnmp_network_panel_get_data
	(GXSNMP_NETWORK_PANEL (dialog->network_panel), dbn);
      if (dbn->rowid == 0)
	network_add (dbn);
      else
	if (changed)
	  network_update (dbn);
      dialog->network_dirty = FALSE;
    }
  dbg = dialog->selected_graph;
  if (dbg)
    {
      changed = gxsnmp_graph_panel_get_data 
	          (GXSNMP_GRAPH_PANEL (dialog->graph_panel), dbg);
      if (dbg->rowid == 0)
	graph_add (dbg);
      else
	if (changed)
	  graph_update (dbg);
    }
  dialog->graph_dirty = FALSE;
  network_refresh_cb (network_sqldb, dbn, G_SQLDB_CB_UPDATE, dialog);
  D_FUNC_END;
}

/****************************************************************************
 * Callback handler for the 'close' signal from the gnome_property_dialog
 ***************************************************************************/
static gint
network_close_cb (GtkWidget *widget, gpointer data)
{
  GXsnmp_network_dialog *dialog;
  D_FUNC_START;
  g_return_val_if_fail (data != NULL, FALSE);
  dialog = GXSNMP_NETWORK_DIALOG (data);
  if (dialog->graph_datalets)
    g_free (dialog->graph_datalets);
  
  D_FUNC_END;
  return FALSE;
}
static void 
network_dialog_help_cb (GtkWidget *widget, gpointer data)
{
  gchar *tmp;
  D_FUNC_START;
  tmp = gnome_help_file_find_file ("gxsnmp", "add-networks.html");
  if (tmp)
    {
      gnome_help_goto (0, tmp);
      g_free (tmp);
    }
  D_FUNC_END;
}
static void
graph_changed_cb (GtkWidget *widget, gpointer data)
{
  D_FUNC_START;
  GXSNMP_NETWORK_DIALOG (data)->graph_dirty = TRUE;
  set_dialog_state (data);
  D_FUNC_END;
}
static void
network_panel_changed_cb (GtkWidget *widget, gpointer data)
{
  D_FUNC_START;
  GXSNMP_NETWORK_DIALOG (data)->network_dirty = TRUE;
  set_dialog_state (data);
  D_FUNC_END;
}

/****************************************************************************
 * Callback to refresh the entire dialog contents
 ***************************************************************************/
static void
network_refresh_cb (G_sqldb_table *table, gpointer row, G_sqldb_cb_type type,
		    gpointer data)
{
  GXsnmp_network_dialog   *dialog;
  GtkCList                *clist;
  GXsnmp_map              *map;
  DB_network              *dbn;
  DB_map                  *cur_dbm;
  GList                   *gl;
  gint                    datalet;
  D_FUNC_START;
  g_return_if_fail (data != NULL);
  dialog   = GXSNMP_NETWORK_DIALOG (data);
  dbn      = (DB_network *)row;

  if (dbn != dialog->selected_network)
    {
      d_print (DEBUG_TRACE, "No network selected.\n");
      D_FUNC_END;
      return;
    }
  /* Fill in the network panel */
  gtk_signal_handler_block_by_data (GTK_OBJECT (dialog->network_panel), 
				    dialog);
  gxsnmp_network_panel_put_data (GXSNMP_NETWORK_PANEL (dialog->network_panel),
				 dbn);
  gtk_signal_handler_unblock_by_data (GTK_OBJECT (dialog->network_panel), 
				      dialog);

  map = gxsnmp_window_get_current_map (GXSNMP_WINDOW (app_info->window));
  if (map)
    {
      d_print (DEBUG_DUMP, "We have at least one map.");
      cur_dbm = map->DB_map;
      clist = GTK_CLIST (dialog->graph_clist);
      gtk_signal_handler_block_by_data (GTK_OBJECT (clist), dialog);
      gtk_clist_freeze (clist);
      gtk_clist_clear (clist);
      if (dialog->graph_datalets)
	g_free (dialog->graph_datalets);
      gl = g_sqldb_table_list (map_sqldb);	/* Loop for each map in the list */
      dialog->graph_datalets = g_new0 (guint, 2 * g_list_length (gl));
      datalet = 0;
      while (gl)
	{
	  DB_map	* dbm = (DB_map *) gl->data;
	  DB_graph  * dbg = NULL;
	  GList	* gl2 = dbn->DB_graphs;
	  gint        row;
	  guint     * row_data;
	  gchar	* entry[2];
	  d_print (DEBUG_TRACE, "Checking maps.");
	  while (gl2)			    /* Look for DB_graph entry */
	    {				    /* for this network on this map */
	      DB_graph *gldbg = (DB_graph *) gl2->data;
	      
	      if (gldbg->map == dbm->rowid)
		{
		  dbg = gldbg; 		        /* Remember DB_graph pointer */
		  break;
		}
	      gl2 = gl2->next;  /* Now dbg points to the DB_graph entry for this */
	    }		    /* network on this map, or NULL if not displayed */
	  
	  entry[0] = dbm->tab;			/* Name of map */
	  entry[1] = dbg ? "Yes" : "No";		/* Display status */
	  row = gtk_clist_append (clist, entry);
	  
	  row_data = &dialog->graph_datalets[datalet];   /* Annoyingly, you can */
	  row_data[0] = dbm->rowid;			     /* only associate one */
	  row_data[1] = dbg ? dbg->rowid : 0;	     /* gpointer with a */
	  gtk_clist_set_row_data (clist, row, row_data); /* CList row */
	  datalet += 2;                                 

	  if (row == dialog->graph_row)
	    {
	      gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), dialog);
	      gtk_clist_select_row (clist, row, 0);
	      gtk_signal_handler_block_by_data (GTK_OBJECT (clist), dialog);
	    }
	  gl = gl->next;
	}
      gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), dialog);
      gtk_clist_thaw (clist);
    }
  else
    {
      d_print (DEBUG_TRACE, "We have no maps..\n");
    }
  D_FUNC_END;
}
static void
set_dialog_state (GXsnmp_network_dialog *dialog)
{
  D_FUNC_END;
  if (dialog->selected_graph)
    {
      gtk_widget_show (dialog->graph_panel);
      gtk_widget_hide (dialog->no_graph_panel);
      gtk_widget_set_sensitive (dialog->graph_show_button, FALSE);
      gtk_widget_set_sensitive (dialog->graph_hide_button, TRUE);
    }
  else
    {
      gtk_widget_hide (dialog->graph_panel);
      gtk_widget_show (dialog->no_graph_panel);
      gtk_widget_set_sensitive (dialog->graph_show_button, TRUE);
      gtk_widget_set_sensitive (dialog->graph_hide_button, FALSE);
    }

  if (dialog->graph_dirty)
    gtk_widget_set_sensitive (dialog->graph_clist, FALSE);
  else
    gtk_widget_set_sensitive (dialog->graph_clist, TRUE);

  if (dialog->selected_network->rowid == 0)
    {
      gtk_widget_set_sensitive (dialog->graph_show_button, FALSE);
      gtk_widget_set_sensitive (dialog->graph_clist, FALSE);
    }
  gnome_property_dialog_set_state (GNOME_PROPERTY_DIALOG (dialog),
				dialog->network_dirty || dialog->graph_dirty);
  D_FUNC_END;
}


/****************************************************************************
 *
 * Public functions to create a new network dialog widget
 *
 * Parameters:
 *
 * dbn -- Either the handle of an existing DB_network entry or NULL if 
 *        this is a call to create a new network.
 *
 * x, y -- Cursor position at the time of the mouse select.
 *
 ***************************************************************************/
GtkWidget *
gxsnmp_network_dialog_new (DB_network *dbn, gdouble x, gdouble y)
{
  GXsnmp_network_dialog    *dialog;
  GXsnmp_map               *map;
  DB_map                   *dbm;
  GList                    *gl;

  D_FUNC_START;
  dialog = gtk_type_new (gxsnmp_network_dialog_get_type ());
  if (!dialog)
    {
      g_warning ("Failed to create the network dialog..");
      return NULL;
    }
  dialog->network_dirty = FALSE;
  dialog->graph_dirty   = FALSE;

  if (!dbn)
    {
      dbn = network_create ();
      dialog->network_dirty = TRUE;
    }
  dialog->x                = x;
  dialog->y                = y;
  dialog->selected_network = dbn;
  
  map = gxsnmp_window_get_current_map (GXSNMP_WINDOW (app_info->window));
  if (map)
    {
      dbm = map->DB_map;
      dialog->selected_graph   = NULL;
      gl = dbn->DB_graphs;
      while (gl)
	{
	  DB_graph  *dbg;
	  dbg = (DB_graph *)gl->data;
	  if (dbg->map == dbm->rowid)
	    {
	      dialog->selected_graph = dbg;
	      break;
	    }
	  gl = gl->next;
	}
    }
  network_refresh_cb (network_sqldb, dbn, G_SQLDB_CB_UPDATE, dialog);
  set_dialog_state (dialog);
  D_FUNC_END;
  return GTK_WIDGET (dialog);
}

/* EOF */

