/*
 * GXSNMP -- An snmp mangament 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
/*  --- WTF Why don't this work???
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#include <stdlib.h>
#endif HAVE_GETOPT_LONG
*/
#include <getopt.h>
#include <strings.h>
#include <signal.h>
#include <libintl.h>

#include "collector.h"

int debug = 0;

static char *cnffile = "collector.conf";
static GHashTable *hostsetup;

static void 
hupsig (int sig)
{
  g_error("HUP - not yet implemented");
}

static void 
init_env (void)
{
  int child;

  if (!debug)
    {
      child = fork ();
      if (child == -1)
	{
	  exit (1);
	}
      if (child == 0)
	{
	  close (0);
	  close (1);
	  close (2);
	  setsid ();
	}
      else
	{
	  exit (0);
	}
    }
  signal (SIGHUP, hupsig);
}

static void 
usage (void)
{
  printf (gettext ("\n"
  "Usage: collector [-c config] [-o outfile] [-p pdusize] [-m maxreq]\n"
  "                 [-t timeout] [-r retry] [-d defer] [-x] [-h]\n"
  "\n"
  "-c config:    configuration file to be used.\n"
  "-x            debug flag.\n"
  "-h            print this message.\n\n"));
  exit (1);
}

static void
fe_intconfig (gpointer key, gpointer value, gpointer user_data)
{
  char *ckey = (gchar *) key;

  if(!strcmp(ckey,"snmp"))
    {
      snmp_init((GHashTable *)user_data);
    }
  else
  if(!strcmp(ckey,"mrtg"))
    {
      mrtg_init((GHashTable *)user_data);
    }
  else
    g_warning("internal module \"%s\" not (yet?) supported", ckey);
}

static void
init_modules (GHashTable *config)
{
  struct slist *module, *external, *internal;

  module = g_hash_table_lookup(config,"modules");
  if (!module)
    g_error("No modules definition");

  if (module->type != SLIST_LIST)
    g_error("Illegal modules definition");

  internal = g_hash_table_lookup(module->value.list,"internal");

  if (internal)
    {
      if (internal->type != SLIST_LIST)
        g_error("Illegal internal definition");
      g_hash_table_foreach(internal->value.list, fe_intconfig, (gpointer) config);
    } 

  external = g_hash_table_lookup(module->value.list,"external");
  if (external)
    {
      if (external->type != SLIST_LIST)
        g_error("Illegal external definition");
      g_warning("external modules not yet supported");
    }
}

static void
fe_hostmodule (gpointer key, gpointer myvalue, gpointer user_data)
{
  struct slist *name, *value;
  char *hostname;
  GHashTable *config;
  cb_host_init cb;

  config = (GHashTable *) user_data;
  cb = (cb_host_init) myvalue;

/* Type already checked in fe_hostconfig */
  value = g_hash_table_lookup(config,"name");
  g_assert(value);
  hostname = value->value.string;

  if ((value = g_hash_table_lookup(config,(char *)key)))
    {
      if (value->type != SLIST_LIST)
        g_error("host module %s illegal", (char *) key);
      cb(value->value.list, hostname);
    }
}

static void
fe_hostconfig (gpointer key, gpointer myvalue, gpointer user_data)
{
  struct slist *name, *value;
  char *hostname;

  name = (struct slist *) myvalue;
  if (name->type != SLIST_LIST)
    g_error("Illegal host %s definition", (char *) key);

  value = g_hash_table_lookup(name->value.list,"name");
  if (!value)
    g_error("host %s has no name", (char *) key);
  if (value->type != SLIST_STRING)
    g_error("host %s name definition illegal", (char *) key);
  hostname = value->value.string;

  printf("Found host %s\n", hostname);
  
  g_hash_table_foreach(hostsetup, fe_hostmodule, name->value.list);
}

static void
init_hosts (GHashTable *config)
{
  struct slist *host;

  host = g_hash_table_lookup(config,"host");
  if (!host)
    g_error("No host definition");
  if (host->type != SLIST_LIST)
    g_error("Illegal host definition");

  g_hash_table_foreach(host->value.list, fe_hostconfig, NULL);
}

void 
register_host_function(char *module, cb_host_init cb)
{
  printf("Registration of %s\n", module);
  g_hash_table_insert(hostsetup, module, cb);
}

int 
main (int argc, char *argv[])
{
  GHashTable *config;
  GMainLoop *loop;

#ifdef HAVE_GETOPT_LONG
  static const struct option long_options[] =
  {
    {"config", 1, 0, 'c'},
    {"debug", 0, 0, 'x'},
    {"help", 0, 0, 'h'},
    {0, 0, 0, 0}
  };
  int oi = 0;
  char *optarg;
#else
  extern char *optarg;
  extern int optind, opterr, optopt;
#endif
  int c;

  hostsetup = g_hash_table_new (g_str_hash, g_str_equal);

#ifdef HAVE_GETOPT_LONG
  while (1)
    {
      c = getopt_long (argc, argv, "c:xh?", long_options,
		       &oi);

      if (c == -1)
	break;

      switch (c)
	{
	case 'c':
	  cnffile = optarg;
	  break;
	case 'x':
	  debug++;
	  break;
	default:
	  usage ();
	  break;
	}
    }
#else HAVE_GETOPT_LONG
  while ((c = getopt(argc, argv, "xc:")) != EOF) {
    switch(c) {
	case 'c':
	  cnffile = optarg;
	  break;
    case 'x':
      debug++;
      break;
    default:
      usage ();
      break;
    }
  }
#endif HAVE_GETOPT_LONG
  if (!read_config_file (cnffile, &config))
    g_error("Error loading config. Exiting...");
    
  init_modules (config);
  init_hosts (config);
  init_env ();

  loop = g_main_new (TRUE);
  while (g_main_is_running (loop))
    {
      g_main_run (loop);
    }
  g_main_destroy (loop);

  return 0;
}

/* EOF */
