/* -*- Mode: C -*-
 *  $Id: main.c,v 1.144 2001/02/23 13:35:02 remlali Exp $
 *  GXSNMP -- An snmp managament 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.
 *
 *  Main program entry point
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <g_sqldb.h>

#include "main.h"
#include "gxsnmp_window.h"
#include "gxsnmp_map.h"
#include "gxsnmp_map_item.h"
#include "gxsnmp_host.h"
#include "gxsnmp_network.h"
#include "gxsnmp_wire.h"
#include "menu_panel.h"
#include "dbapi.h"
#include "gxsnmp/gxsnmp_dbapi.h"			/* Client API */

void debug(){}
GIOChannel *ddchannel;


#define __IN_MAIN_C__
#include "debug.h"
extern G_sql gxsnmp_sql_database;

/****************************************************************************
 *
 * Local functions 
 *
 ***************************************************************************/

static void quit_button_cb                           (GtkWidget    *widget,
				                      gpointer     data);
static void make_init_status_window                  ();
static void init_text_draw                           (GtkWidget    *widget);
static void destroy_init_status_window               ();
static void sync_display                             ();
static void notification_cb(GIOChannel *channel,gint type,guint rowid,
                            gchar *table,gpointer data);
/****************************************************************************
 * Global data allocated in this module.
 ***************************************************************************/
gxsnmp                      *app_info;
int                         debug_level;
int                         trace_level;
gchar                       *pixmap_path;
gchar                       *mib_path;
/****************************************************************************
 *
 *  Local data
 *
 ****************************************************************************/
static GtkWidget     *initstatus      = NULL;
static GtkWidget     *label1          = NULL;
static GtkWidget     *label2          = NULL;
static GtkWidget     *logo_area       = NULL;
static int           logo_area_width  = 0;
static int           logo_area_height = 0;
#define LOGO_WIDTH_MIN 300
#define LOGO_HEIGHT_MIN 140
/****************************************************************************
 * Any options we will parse.
 ***************************************************************************/
static const struct poptOption gxsnmp_opts[] = 
{
  { "pixmap-path", '\0', POPT_ARG_STRING, &pixmap_path, 0, 
    N_("Full path to the pixmap files"), N_("PATH") },
  { "mib-path", '\0', POPT_ARG_STRING, &mib_path, 0, 
    N_("Path to where the MIB file(s) are located."), N_("PATH") },
  { "debug-level", '\0', POPT_ARG_INT, &debug_level, 0,
    N_("Enables debugging messages."), N_("LEVEL") },
  { NULL, '\0', 0, NULL, 0}
};

/*** Database notification callback ***/
static void
notification_cb (GIOChannel *channel, gint type, guint rowid,
                 gchar *table, gpointer data)
{
  DB_interface  * dbi;
  DB_host       * dbh;
  gchar         * oldtag;

  dbi = g_sqldb_row_find(interface_sqldb, "_rowid", &rowid);
  if(dbi){
    oldtag = g_strdup(dbi->tags);
    g_sqldb_reload_row(interface_sqldb, dbi);
    dbi = g_sqldb_row_find(interface_sqldb, "_rowid", &rowid);
    dbh = g_sqldb_row_find(host_sqldb, "_rowid", &dbi->host);
    if(dbi && dbh)
      fprintf(stderr,"Host %s, Interface %s(%s) is %s\n", 
              dbh->name, dbi->name, dbi->address, dbi->tags);
  }
}

/****************************************************************************
 *
 *  Main program entry point
 *
 ***************************************************************************/
gint 
main (int argc, char *argv[])
{
  int             time_id, rc, pathlen;
  app_event       event;
  struct passwd * passwd;
  GList 	* gl;
  GList		* bad_records;
  char		* oldpath, *newpath;

  bindtextdomain (PACKAGE, GNOMELOCALEDIR);
  textdomain (PACKAGE);                 
  gnome_init_with_popt_table ("gxsnmp", VERSION, argc, argv, 
			      gxsnmp_opts, 0, NULL);
  make_init_status_window ();
  init_text_draw (logo_area);
/*
 * Actually lets load em _after_ we have set up the gnome libs so that they
 * have access to gnome libs and such...
 * Load the plugins first.  This maximizes the ability of the plugins to
 * modify program behavior
 */
  app_update_init_status ("Loading plugins....", NULL);

#ifdef USE_GLE
  gle_init (&argc, &argv);
#endif

  passwd = getpwuid (getuid());

/*
**  A lot of this stuff is obsolete, and should be cleaned up -- jms
*/

  app_info = (gxsnmp *)g_malloc (sizeof (gxsnmp));
  app_info->x = 1;
  app_info->y = 1;
  app_info->current_host = NULL;
  app_info->conf_panel  = NULL;

  app_info->summary_dialog = NULL;
  app_info->database_dialog = NULL;
  
  app_info->summary.host_count          = 0;
  app_info->summary.network_count       = 0;
  app_info->root_width                  = gdk_screen_width ();
  app_info->root_height                 = gdk_screen_height ();

/*
**  Provide a linked list of available SNMP versions, as well as a list
**  of descriptive labels. A bit less descriptive (to wordy).
*/

  app_info->version_names = NULL;
  app_info->version_values = NULL;
  app_info->version_names = g_list_append(app_info->version_names,
                                _("Version 1"));
  app_info->version_values = g_list_append(app_info-> version_values,
                                GINT_TO_POINTER(PMODEL_SNMPV1));
  app_info->version_names = g_list_append(app_info->version_names,
                                _("Version 2c"));
  app_info->version_values = g_list_append(app_info-> version_values,
                                GINT_TO_POINTER(PMODEL_SNMPV2C));
  app_info->version_names = g_list_append(app_info->version_names,
                                _("Version 2"));
  app_info->version_values = g_list_append(app_info-> version_values,
                                GINT_TO_POINTER(PMODEL_SNMPV2));
  app_info->version_names = g_list_append(app_info->version_names,
                                _("Version 3"));
  app_info->version_values = g_list_append(app_info-> version_values,
                                GINT_TO_POINTER(PMODEL_SNMPV3));

  event.category     = GX_EVENT_INFO;
  event.sub_category = GX_INFO_NONE;
  event.timestamp    = time (NULL);
  event.description  = g_strdup ("gxsnmp started.");
  add_event (&event);
  gtk_rc_parse ("gxsnmpgtkrc");
  d_print (DEBUG_DUMP, "PID: [%d]\n", getpid());

  smiInit("gxsnmp");
  if (!mib_path) mib_path=MIBDIR;
  oldpath = smiGetPath();
  pathlen = strlen(oldpath) + strlen(mib_path) + 2;
  newpath = g_malloc(pathlen);
  snprintf(newpath, pathlen, "%s:%s", oldpath, mib_path);
  smiSetPath(newpath);
  if (debug_level & 1)
    smiSetErrorLevel(10);
  else
    smiSetErrorLevel(1);
  smiSetFlags(SMI_FLAG_ERRORS|SMI_FLAG_STATS);

  /* We will die if the lib can't be init'd... Should be dealt with better.
   */
  if (!g_snmp_init (FALSE))
    g_error ("Failed to initialize the SNMP library.");
  
  if (getuid() != 0)
    {
      /*
       * Maybe do a dialog here or set a flag telling the user that 
       * ping and traceroute will be disabled because they are not running as
       * root?
       */
    }
  else
    {
      initpingsocket();
      initping();
    }

/*
**  Set up all defaults.
*/

  app_info->snmp_running = 0;

  load_config ();   /* Load the user configuration file if present */

/*
**  Build the main application window
*/

  app_info->window = gxsnmp_window_new ();
  gtk_signal_connect (GTK_OBJECT (app_info->window), "destroy",
                      (GtkSignalFunc) quit_button_cb, NULL);
  gtk_widget_show (app_info->window);


/* start the Virtual Database System */

  ddchannel = db_server_connect_config ("127.0.0.1", 4000);
  db_notification_add (notification_cb);

/*
**  Call table_load_topology () to load in the snmp, host, interface,
**  and network tables.  
*/

  table_load_topology (ddchannel);

/*
**  Read in the map table and create all of the application maps.
*/

  map_sqldb->channel = ddchannel;
  g_sqldb_table_load (map_sqldb);
  gl = g_sqldb_table_list (map_sqldb);
  while (gl)
    {
      DB_map	 * dbm;
      GXsnmp_map * map;

      dbm = (DB_map *) gl->data;

      map = dbm->application = gxsnmp_map_new ();
      map->DB_map = dbm; 

      gxsnmp_map_set_name (GXSNMP_MAP (dbm->application), dbm->name);
      gtk_widget_show (GTK_WIDGET (dbm->application));
      gxsnmp_window_add_map (GXSNMP_WINDOW (app_info->window),
			     GXSNMP_MAP    (map));
      gl = gl->next;
    }

/*
**  Read in the graph table, and connect the host and network pointers to the
**  correct database blocks.  Also create the host and network graphical 
**  objects, but not the wire objects.
*/

#if 0
  gtk_type_class(gxsnmp_host_get_type()); /*this chunk goes with graph_load()*/
  gtk_type_class(gxsnmp_network_get_type());
  gtk_type_class(gxsnmp_wire_get_type());
#endif

  graph_sqldb->channel = ddchannel;
  bad_records = graph_load ();

  if (bad_records)
    {
      gchar c;

      g_print ("gxsnmp:  %d bad graph records were found.  Enter 'd' "
	       "to delete them, or 'q' to quit.\n",
	       g_list_length (bad_records));
      do
	c = getchar();
      while (c != 'd' && c != 'q');

      if (c == 'q') 
	exit(1);

      gl = bad_records;
      while (gl)
	{
	  g_sqldb_row_delete (graph_sqldb, gl->data);
	  gl = gl->next;
	}
      g_list_free (bad_records);
    }

/*
**  Now that all of the host and network map entries are created, we can 
**  add the connecting wires. 
*/

  gl = g_sqldb_table_list (graph_sqldb);
  while (gl)
    {
      DB_graph          * dbg;

      dbg = (DB_graph *) gl->data;

      if (dbg->type == DB_GRAPH_WIRE)
	gxsnmp_wire_new (dbg);
  
      gl = gl->next;
    }

/*
**  Finished constructing the in-storage database.  Now we can start the
**  collector and the application plugins.
*/



/*
  plugins_start (PLUGIN_COLLECTOR | PLUGIN_APPLICATION);
*/

/*
**  Set a timeout so that the event queue starts running in one second
*/

  time_id = gtk_timeout_add (1000, run_queue, NULL);

  d_print (DEBUG_TRACE, "Entering gtk_main loop\n");
  destroy_init_status_window ();

  gtk_main();

  d_print (DEBUG_TRACE, "Exiting gtk_main loop\n");
  g_mem_profile ();
  return 0;
}

/******************************************************************************
**
**  Termination code
**
**  This callback is invoked when the user either quits the application or
**  uses window manager functions to close the application.
**
**  Clean up everything we can, then call gtk_main_quit, which will cause
**  gtk_main (above) to terminate.  main() will then exit.
**
**  quit_app() is the public function.  quit_button_cb is the private
**  callback function.
**
******************************************************************************/

void
quit_app ()
{
  quit_button_cb (NULL, NULL);
}

static void
quit_button_cb (GtkWidget *widget, gpointer  data)
{
  g_print ("Quit button callback invoked\n");
  db_plugins_unload ();
  close_file_dialog ();
  destroy_summary_dialog ();
  if (app_info->conf_panel)
      gtk_widget_destroy (app_info->conf_panel);
  destroy_monitor_panel ();
  destroy_set_panel ();
  destroy_get_panel ();
  destroy_event_panel ();

  db_server_disconnect(ddchannel);

  gtk_main_quit();
}

/******************************************************************************
**
**  Function to update the statusbar
**
******************************************************************************/

void
update_statusbar (gchar * format, ...)
{
  gchar   * statusline;
  va_list   args;

  va_start (args, format); 
  statusline = g_strdup_vprintf (format, args);
  va_end (args);

  gxsnmp_window_set_statusbar_text (GXSNMP_WINDOW (app_info->window), 
				    statusline);
  g_free (statusline);
}

/****************************************************************************
 * Initial splash screen code. Everyone loves splash screens... :)
 * Alot of this shamelessly ripped from the bowels of GIMP...
 */
/* 
 * Draw the text in the window 
 */
static void
init_text_draw (GtkWidget *widget)
{
  GdkFont *font = NULL;

  font = gdk_font_load ("-Adobe-Helvetica-Bold-R-Normal--*-130-*-*-*-*-*-*");
  gdk_draw_string (widget->window,
		   font,
		   widget->style->fg_gc[GTK_STATE_NORMAL],
		   ((logo_area_width - gdk_string_width (font, "GXSNMP")) /2),
		   (0.25 * logo_area_height),
		   "GXSNMP");
  gdk_font_unref (font);
  font = gdk_font_load ("-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*");
  gdk_draw_string (widget->window,
		   font,
		   widget->style->fg_gc[GTK_STATE_NORMAL],
		   ((logo_area_width - gdk_string_width (font, VERSION)) / 2),
		   (0.45 * logo_area_height),
		   VERSION);
  gdk_font_unref (font);
}

static void
init_window_expose (GtkWidget *widget)
{
   init_text_draw (widget);
}


static void
destroy_init_status_window ()
{
  if (initstatus)
    gtk_widget_destroy (initstatus);
}

static void
make_init_status_window ()
{
  GtkWidget *vbox;

  initstatus = gtk_window_new (GTK_WINDOW_DIALOG);
  gtk_signal_connect (GTK_OBJECT (initstatus), "delete_event",
		      (GtkSignalFunc) gtk_true,
		      NULL);
  gtk_window_set_wmclass (GTK_WINDOW (initstatus), "gxsnmp_startup",
			  "GXSNMP");
  gtk_window_set_title (GTK_WINDOW (initstatus), "GXSNMP starting...");

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_add (GTK_CONTAINER (initstatus), vbox);
  logo_area = gtk_drawing_area_new ();
  gtk_signal_connect (GTK_OBJECT (logo_area), "expose_event",
                      (GtkSignalFunc) init_window_expose, NULL);
  logo_area_width  = LOGO_WIDTH_MIN;
  logo_area_height = LOGO_HEIGHT_MIN;
  gtk_drawing_area_size (GTK_DRAWING_AREA (logo_area), logo_area_width,
                         logo_area_height);
  gtk_box_pack_start_defaults (GTK_BOX (vbox), logo_area);
  label1 = gtk_label_new ("");
  gtk_box_pack_start_defaults (GTK_BOX (vbox), label1);
  label2 = gtk_label_new ("");
  gtk_box_pack_start_defaults (GTK_BOX (vbox), label2);
  gtk_window_position (GTK_WINDOW (initstatus), GTK_WIN_POS_CENTER);
  gtk_widget_show_all (vbox);
  gtk_widget_show_now (initstatus);
  sync_display ();
}

/* Spin till all gtk events have been processed. */
static void
sync_display ()
{
  while (gtk_events_pending ())
    gtk_main_iteration ();
  gdk_flush ();
}

/* Update the init stat... */
void 
app_update_init_status (gchar *lab1, gchar *lab2)
{
  if (lab1 && strcmp (lab1, GTK_LABEL (label1)->label))
    gtk_label_set (GTK_LABEL (label1), lab1);
  if (lab2 && strcmp (lab2, GTK_LABEL (label2)->label))
    gtk_label_set (GTK_LABEL (label2), lab2);
  sync_display ();
}

/* EOF */
