/*
 * Debug logging support for japhar
 *
 * To start logging, compile japhar with -DLOG (or edit include/config.h)
 * and set the following in environment:
 *  export JAPHAR_LOG=ALL,20,japhar.log
 *
 * Example names is:
 *  Interp, InterpLoop, OpStack, DO_METHOD_CALL, NativeGlue,
 *  ClassRepository, Resolve, ObjectRef, ParseClass
 *
 *  ALL means log everthing.
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "native-threads.h"
#include "log.h"
#include "compat.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
  char *log;
  int level;
  char *filename;
  FILE *fp;
} log_table_entry;

log_table_entry *logs = NULL;
int num_logs = 0;
int alloc_logs = 0;

static char *JAPHAR_LOG = NULL; /* the environment variable */

static void
add_log_entry(char *log_name, int level, char *filename)
{
  if (alloc_logs == 0)
    {
      alloc_logs = (alloc_logs + 1) * 2;
      logs = (log_table_entry*)malloc(sizeof(log_table_entry) * alloc_logs);
    }
  else if (alloc_logs == num_logs)
    {
      alloc_logs = (alloc_logs + 1) * 2;
      logs = (log_table_entry*)realloc(logs, sizeof(log_table_entry) * alloc_logs);
    }

  logs [ num_logs ].log = strdup(log_name);
  logs [ num_logs ].level = level;

  if (filename == NULL)
    {
      logs [ num_logs ].filename = NULL;
      logs [ num_logs ].fp = stdout;
    }
  else
    {
      logs [ num_logs ].filename = strdup(filename);
      logs [ num_logs ].fp = NULL;
    }

  num_logs ++;
}

#ifdef LOGGING
static log_table_entry *
log_entry_find(char *name)
{
  int i;

  for (i = 0; i < num_logs; i ++)
    {
      if (!strcmp(name, logs[i].log))
	return &(logs[i]);
    }
  if (0 == strcmp("ALL", name))
    return NULL;

  return log_entry_find("ALL");
}
#endif

static void
parse_env(void)
{
  char working_log_entry[100];
  char *p,*q;
  char log_name[100];
  int level;

  JAPHAR_LOG = getenv("JAPHAR_LOG");

  while (JAPHAR_LOG != NULL)
    {
      p = strchr(JAPHAR_LOG, ':');
      
      if (p == NULL)
	{
	  strcpy(working_log_entry, JAPHAR_LOG);
	  JAPHAR_LOG = NULL;
	}
      else
	{
	  strncpy(working_log_entry, JAPHAR_LOG, (int)(p - JAPHAR_LOG));
	  working_log_entry[(int)(p - JAPHAR_LOG)] = 0;
	  JAPHAR_LOG = p + 1;
	}
      
      /* now we parse the individual entry */

      /* nothing to do if the env var has '::' in it. */
      if (strlen(working_log_entry) == 0)
	continue;

      q = working_log_entry;
      p = strchr(q, ',');
      
      if (p == NULL) /* there is only a log name */
	{
	  strcpy(log_name, q);
	  add_log_entry(log_name, 1, NULL);
	}
      else
	{
	  strncpy(log_name, q, (int)(p - q));
	  log_name[(int)(p - q)] = 0;
	  q = p + 1;

	  p = strchr(q, ',');
	  
	  if (p == NULL) /* there is only a log name and level */
	    {
	      level = atoi(q);
	      add_log_entry(log_name, level, NULL);
	    }
	  else
	    {
	      /* there are all three entries. */
	      level = atoi(q);
	      q = p + 1;

	      if (*q == '\0')
		add_log_entry(log_name, level, NULL);
	      else
		add_log_entry(log_name, level, q);
	    }
	}
    }
  
}

static void
debug_log_table(void)
{
  int i;

  for (i = 0; i < num_logs; i ++)
    {
      printf ("LOG NAME:  '%s'\t\tLOG LEVEL:  %d\t\tLOG_FILE:   %s\n", 
	      logs[i].log, logs[i].level,
	      logs[i].filename ? logs[i].filename : "(null)");
    }
}

#ifdef LOGGING
static FILE *
LOG_getStream(char *logname)
{
  int i;

  for (i = 0; i < num_logs; i ++)
    if (!strcmp(logname, logs[i].log))
      return logs[i].fp;

  /* this should be an error... */
  return NULL;
}
#endif

void
LOG_init()
{
  static int initted = 0;

  if (!initted)
    {
      parse_env();
      debug_log_table();
      initted = 1;
    }
}

void
LOG_log(char *log, int level, char *msg_format, ...)
{
#ifdef LOGGING
  va_list ap;
  log_table_entry *foo = log_entry_find(log);
  
  if (foo && foo->level >= level)
    {
      char strbuf[200];
      char *eol;

      va_start(ap, msg_format);
      vsnprintf(strbuf, sizeof(strbuf), msg_format, ap);
      va_end(ap);

      eol = strrchr(strbuf, '\n');

      if (foo->filename != NULL && foo->fp == NULL)
	foo->fp = fopen(foo->filename, "w");

      if (NULL == eol)
	{
	  fwrite(strbuf, strlen(strbuf), 1, foo->fp);
	}
      else
	{
	  *eol = 0;
	  fwrite(strbuf, strlen(strbuf), 1, foo->fp);
	  fprintf(foo->fp, " thr=0x%x\n", (int)THREAD_getCurrent());

	  /* More stuff after last \n? */
	  eol++;
	  if (0 < strlen(eol))
	    {
	      fwrite(eol, strlen(eol), 1, foo->fp);
	    }
	}

      fflush(foo->fp);
    }
#endif  
}
