/*
**  GXSNMP -- An snmp management application
**
**  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.
**
**  traffic.c -- An interface traffic monitor for GXSNMP
**
*/

#define DEBUG

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <glib.h>
#include "plugins.h"
#include "main.h"
#include "tables.h"
#include "traffic_dialog.h"

extern gxsnmp * app_info;

/******************************************************************************
**
**  Local data structures
**
******************************************************************************/

/*
**  One of these blocks exists for each interface known to GXSNMP.  It
**  contains both the data blocks needed for the snmp queries, and a
**  list of saved state information needed from request to request.
*/

typedef struct _if_data
{
  host_snmp	host;		/* Host SNMP structure for _get request */
  GSList      * pdu;		/* GSList of PDUs to obtain for interface */
  gpointer	request;	/* Return value from g_async_get */ 

  guint		rowid;		/* Rowid of this interface */
  guint		timestamp;	/* Timestamp of data in if_data block */
  guint		speed;		/* Rated interface speed */
  guint		state;		/* Operational state of the interface */
  guint		received;	/* Octets-received counter as of (timestamp) */
  guint		sent;		/* Octets-sent counter as of (timestamp) */
}
if_data;

/******************************************************************************
**
**  Forward references
**
******************************************************************************/

static void 	menu_callback  (GtkWidget 	* widget, 
			 	gpointer 	  data);

static void 	initialize     (void);

static void     start_request  (void);

static gboolean completed_cb   (host_snmp 	* host,
				gpointer    	  data,
              			SNMP_PDU  	* pdu,
              			GSList    	* objs);

static void 	timeout_cb     (host_snmp 	* host,
            			gpointer    	  data);

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

static gchar 	  * menu_location	= NULL;
static GList 	  * interfaces		= NULL;			
static GHashTable * interface_hash 	= NULL;

/******************************************************************************
**
**  The plugin load routine
**
******************************************************************************/

gint
load_plugin (PluginData * pd)
{
  pd->type = PLUGIN_APPLICATION;
  return 0;
}

/******************************************************************************
**
**  The plugin unload routine
**
******************************************************************************/

void
unload_plugin (PluginData * pd)
{
#ifdef DEBUG
  g_print ("traffic plugin unloaded\n");
#endif
}

/******************************************************************************
**
**  The plugin start routine 
**
******************************************************************************/

gint 
start_plugin (PluginData * pd)
{
  GnomeUIInfo   * menu;
#ifdef DEBUG
  g_print ("Starting traffic plugin.\n");
#endif 
  menu_location         = g_strdup_printf ("%s/", gettext("_Plugins"));

  menu 			= g_malloc0 (2 * sizeof(GnomeUIInfo));
  menu->type		= GNOME_APP_UI_ITEM;
  menu->label           = g_strdup ("Keepalive");
  menu->hint            = NULL;
  menu->moreinfo        = menu_callback;       /* Menu activation cb routine */
  menu->user_data       = NULL;		       /* User data for the callback */
  menu->unused_data     = NULL;                /* Reserved for future use */
  menu->pixmap_type     = 0;
  menu->pixmap_info     = NULL;
  menu->accelerator_key = 0;
  (menu + 1)->type      = GNOME_APP_UI_ENDOFINFO;

  gnome_app_insert_menus (GNOME_APP (app_info->window), menu_location, menu);

  initialize ();

  return 0;
}

/******************************************************************************
**
**  Callback handler for when 'traffic' is selected from the 'plugins' menu
**
**  Create the dialog widget and hand it over to the dialog manager.
**
******************************************************************************/

static void
menu_callback (GtkWidget * widget, gpointer data)
{

#ifdef FIXME
  GtkWidget       * dialog_widget;

  if (!gxsnmp_dialog_check ("traffic_plugin", NULL))
    {
      dialog_widget = gxsnmp_keepalive_dialog_new ();
      if (dialog_widget)
        gxsnmp_dialog_add (dialog_widget, "Keepalive Plugin", NULL,
                           g_strdup ("Keepalive Plugin"));
    }
#endif

}

/******************************************************************************
**
**  Initialize function for the traffic queue 
**
******************************************************************************/

static void
initialize (void)
{
  interfaces     = NULL;
  interface_hash = g_hash_table_new (g_int_hash, g_int_equal);
  start_request ();		/* Initiate the first query operation */
}

/******************************************************************************
**
**  Subroutine to start a network traffic polling operation. 
**
**  The first step is to resynchronize the plugin's internal list of
**  monitored interface with the GXSNMP database.  This is done by
**  running through the database, and adding any new entries, then
**  running through our internal list, and removing any obsolete entries.
**
******************************************************************************/

static void
start_request ()
{
  DB_interface  * dbi;	/* Interface structure */
  GList		* gl;
  GList		* entry;
  if_data	* ifd;

  g_print ("start_request: Looking for newly added interfaces\n");

  gl = g_sqldb_table_list (interface_sqldb);
  while (gl)
    {
      dbi = (DB_interface *)gl->data;
      entry = g_hash_table_lookup (interface_hash, &dbi->rowid);
      if (entry == NULL)
	{
          ifd = g_new0 (if_data, 1);
	  ifd->rowid = dbi->rowid;
          interfaces = g_list_append (interfaces, ifd);
	  g_hash_table_insert (interface_hash, ifd, &ifd->rowid);
	  g_print ("%d ", ifd->rowid);
	}
      gl = gl->next;
    }

  g_print ("\nstart_request: Looking for removed interfaces\n");

  gl = interfaces;
  while (gl)
    {
      ifd = (if_data *)gl->data;
      dbi = g_sqldb_row_find (interface_sqldb, "_rowid", &ifd->rowid);
      if (dbi == NULL)
	{
          /*  FIXME:  Make sure that there isn't a request in progress */
	  g_print ("%d", ifd->rowid);
	  g_hash_table_remove (interface_hash, &ifd->rowid);
          interfaces = g_list_remove (interfaces, ifd);
	  g_free (ifd);
        } 
      gl = gl->next;
    }

  g_print ("\nstart_request:  table updated\n");
}

void send_request ()
{
/*
  DB_interface  * dbi;
  DB_snmp 	* dbs;
  GList         * gl;

  if (!(dbi = g_sqldb_row_find (interface_sqldb, "_rowid", &ka->rowid)))
    return FALSE;

  if (!(dbs = (DB_snmp *) dbi->DB_snmp))
      return FALSE;

  ka->pdu = NULL;

  g_pdu_add_name (&ka->pdu, "system.sysUpTime.0",
		  SNMP_NULL, NULL);

  g_pdu_add_name (&ka->pdu, "interfaces.ifTable.ifEntry.ifSpeed.0",
		  SNMP_NULL, NULL);

  g_pdu_add_name (&ka->pdu, "interfaces.ifTable.ifEntry.ifOperStatus.0",
		  SNMP_NULL, NULL);

 FIXME:  We need to free the following memory when the request finishes 

  mib = g_strdup_printf ("interfaces.ifTable.ifEntry.ifInOctets.%s",
			 dbi->address);
  g_pdu_add_name (&ka->pdu, mib, SNMP_NULL, NULL);

  g_pdu_add_name (&ka->pdu, "interfaces.ifTable.ifEntry.ifOutOctets.0",
		  SNMP_NULL, NULL);

  ka->host.domain	    = dbi->transport;
  ka->host.rcomm	    = dbs->read_c  ? g_strdup (dbs->read_c) : NULL;
  ka->host.wcomm	    = dbs->write_c ? g_strdup (dbs->write_c) : NULL;
  ka->host.retries	    = dbs->retries;
  ka->host.name		    = g_strdup (dbi->address ? dbi->address : "");
  ka->host.status      	    = 0;
  ka->host.port		    = dbs->port;
  ka->host.timeout	    = dbs->timeout;
  ka->host.version     	    = dbs->version;
  ka->host.done_callback    = completed_cb;
  ka->host.time_callback    = timeout_cb;
  ka->host.magic	    = ka;		   Address of control block 

  ka->request = g_async_get (&ka->host, ka->pdu);
#ifdef DEBUG
  g_print ("traffic.c/send_request: Request sent to %s, request ID %x\n", 
		dbi->address, (guint)ka->request);
#endif
*/
}

/******************************************************************************
**
**  Callback for when a request completes
**
******************************************************************************/

static gboolean
completed_cb (host_snmp * host,		/* Pointer to host_snmp structure */
	      gpointer	  data,		/* User data pointer */
	      SNMP_PDU	* spdu,		/* We don't use this yet */
	      GSList    * objs)		/* Returned list of objects */
{
/*
  tr_data * ka;
  int       i;

  ka = (tr_data *) data;
#ifdef DEBUG
  g_print ("traffic.c/completed_cb: Completed request %x\n", 
		(guint )ka->request);
#endif
  if (host->status)
    {
#ifdef DEBUG
      g_print ("SNMP engine reported error: ");
      switch(host->status)
        {
          case SNMP_TOOBIG:
            g_print ("PDU too big\n");
            break;
          case SNMP_NOSUCHNAME:
            g_print ("No such name\n");
            break;
          case SNMP_BADVALUE:
            g_print ("Bad value\n");
            break;
          case SNMP_READONLY:
            g_print ("Read only\n");
            break;
          case SNMP_GENERROR:
            g_print ("Generic error\n");
            break;
          default:
            g_print ("unknown: %d\n", host->status);
            break;
        }
#endif
      return TRUE;
    }

  while (objs)
    {
      SNMP_OBJECT * obj;

      obj = (SNMP_OBJECT *) objs->data;
#ifdef DEBUG
      g_print ("Object MIB = ");
      for (i = 0; i < obj->id_len; i++)
        {
	  g_print ("%d", obj->id[i]);
	  if (i < obj->id_len)
	    g_print (".");
	}
      g_print (" data:\n%s\n", obj->syntax.c);
#endif
      objs = objs->next;
    }
*/
  return TRUE;
}

/******************************************************************************
**
**  Callback for when a request times out
**
******************************************************************************/

static void
timeout_cb (host_snmp * host, 
	    gpointer    data)
{
/*
  tr_data * ka;

  ka = (tr_data *)data;
#ifdef DEBUG
  g_print ("Request timed out %x\n", (guint )ka->request);
#endif
*/
}

/* EOF */
