/*
 * GXSNMP -- An snmp management application.
 * Copyright (C) 1998 Jochen Friedrich
 *
 * 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.
 *
 * config.c -- Configuration file handling.
 */
#include <config.h>    /* -- autoconf groked stuff */
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <glib.h>
#define TEST
#include "collector.h"

GHashTable * 
check_or_add_sublist(gchar *id, GHashTable *config)
{
  struct slist  *list;
  GHashTable    *subconf;

  list = g_hash_table_lookup(config, id);
  if (list)
    {
      if (list->type == SLIST_LIST)
        return list->value.list;
      else return NULL;
    }
  subconf = g_hash_table_new(g_str_hash, g_str_equal);
  list = (struct slist *) g_malloc(sizeof(struct slist));
  list->type = SLIST_LIST;
  list->value.list = subconf;
  g_hash_table_insert(config, id, list);
  return subconf;
}

gboolean
add_branch (gchar *id, GScanner *scanner, GHashTable *config)
{
  GTokenType     token;
  struct slist  *list;
  GHashTable    *subconf;

  while (1) 
    {
      token = g_scanner_get_next_token (scanner);

      if (token == G_TOKEN_EOF)
        return FALSE;

      switch (token)
        {
          case ';':
	    subconf = check_or_add_sublist(id, config);
            if (!subconf) return FALSE;
            return TRUE;
            
          case '{':
            subconf = check_or_add_sublist(id, config);
	    if (!subconf)
              return FALSE;
            while(1)
              {
                token = g_scanner_get_next_token (scanner);
	        switch (token)
	          {
                    case G_TOKEN_IDENTIFIER:
                      id = g_strdup(scanner->value.v_string);
		      if (!add_branch(id, scanner, subconf))
                        return FALSE;
                      break;
                    case '}':
                      goto close;
                    default:
                      return FALSE;
                  }
              }
            close:
            token = g_scanner_get_next_token (scanner);
            if (token != ';')
              return FALSE;
            return TRUE;

          case G_TOKEN_IDENTIFIER:
            subconf = check_or_add_sublist(id, config);
            if (!subconf)
              return FALSE;
            id = g_strdup(scanner->value.v_string);
            return add_branch(id, scanner, subconf);

          case '=':
            list = (struct slist *) g_malloc(sizeof(struct slist));
            token = g_scanner_get_next_token (scanner);
            switch (token)
              {
                case G_TOKEN_STRING:
                  list->type = SLIST_STRING;
	          list->value.string = g_strdup(scanner->value.v_string);
                  break;

                case G_TOKEN_INT:
                  list->type = SLIST_NUM;
	          list->value.number = scanner->value.v_int;
                  break;

                default:
                  return FALSE;
              }
            if (g_hash_table_lookup(config, id))
              return FALSE;
            g_hash_table_insert(config, id, list);
            token = g_scanner_get_next_token (scanner);
            if (token != ';')
              return FALSE;
            return TRUE;
          default:
            return FALSE;
	}
    }
}

gboolean
read_config_file (gchar *filename, GHashTable **config)
{
  gint           fd;
  GScanner     * scanner;
  GTokenType     token;
  char         * id;

  *config = g_hash_table_new(g_str_hash, g_str_equal);

  if (filename)
    {
      fd = open (filename, O_RDONLY);
      if (fd < 0)
	{
	  g_warning ("Unable to open config file %s: %s\n", filename, 
		     g_strerror (errno));
	  return FALSE;
	}
      scanner = g_scanner_new (NULL);
      g_scanner_input_file (scanner, fd);
      scanner->input_name = filename;
      while (1) 
	{
	  token = g_scanner_get_next_token (scanner);

	  if (token == G_TOKEN_EOF)
	      goto finished;
	  
	  switch (token)
	    {
              case G_TOKEN_IDENTIFIER:
                id = g_strdup(scanner->value.v_string);
		add_branch(id, scanner, *config);
                break;

              default:
                goto error;
	    }
	}
    error: 
      g_scanner_error (scanner, "Error parsing config file\n");
      return FALSE;
    finished:
      g_scanner_destroy (scanner);
      close (fd);

      return TRUE;
    }
  return FALSE;
}

#ifdef TEST

void
do_dump(gpointer key, gpointer value, gpointer user_data)
{
  int i,j;
  char *ckey;
  struct slist *list;

  i    = *(int *)user_data;
  ckey = (gchar *) key;
  list = (struct slist *) value;

  for (j=0; j<i; j++)
    printf("  ");
  printf("%s ", ckey);
  switch (list->type)
    {
      case SLIST_NUM:
        printf("= %d\n", list->value.number);
        break;
      case SLIST_STRING:
        printf("= \"%s\"\n", list->value.string);
        break;
      case SLIST_LIST:
        printf("\n");
        j=i+1;
        g_hash_table_foreach(list->value.list, do_dump, &j);
        break;
      default:
        printf("This should never happen\n");
    }
}

void
dump_config(GHashTable *config)
{
  int i;
  i = 0;
  g_hash_table_foreach(config, do_dump, &i);
};

int 
foo_main()
{
  GHashTable * config;

  read_config_file("sample.conf", &config);

  printf("Dumping...\n");
  dump_config(config);
  return 0;
}

#endif

/* EOF */
