/* reports.c -- Use this module to check all the others! ;-)
 *
 * This file is part of TUA.
 * 
 *   Copyright (C) 1991,96  Lele Gaifax
 *
 *   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, Boston, MA 02111-1307, USA.
 *
 */

#include "tua.h"
#include "pcdl.h"

extern PTR EXFUN(malloc, (size_t));

static void EXFUN (systems_summary_header, (NOARGS));
static void EXFUN (systems_summary_table_header, (NOARGS));

#define BYTES_PER_KBYTE 1024.0
#define BYTES_PER_MBYTE (BYTES_PER_KBYTE*1000.0)
#define BYTES_PER_GBYTE	(BYTES_PER_MBYTE*1000.0)

#define NotZero(rec)	\
    ((rec).Out.Files || (rec).In.Files || (rec).Out.Bytes || (rec).In.Bytes || \
     (rec).Out.Time || (rec).In.Time)

static char *			/* Transforms seconds to "hh:mm:ss" */
DEFUN (time_to_string, (tim),
       double tim)
{
  char *str;
  int hh, mm, ss;
  register time_t ltim = (time_t) tim;

  ltim = (time_t) tim;
  hh = (int) (ltim / 3600L);
  ltim %= 3600L;
  mm = (int) (ltim / 60L);
  ss = (int) (ltim % 60L);
  str = (char *) malloc (sizeof "HHHH:MM:SS.hh");
  sprintf (str, "%4d:%02d:%02d.%02d",
	   hh, mm, ss, (int) ((tim - (int) (tim)) * 100));
  return (str);
}

static void
DEFUN (print_the_command, (comm),
       CONST command_rec_t * comm)
{
  if (comm->Number > 1)
    printf ("\t(%4u) ", comm->Number);
  else
    printf ("\t       ");
  printf ("%s\n", comm->Command);
}

static void
DEFUN (print_the_system, (system),
       CONST system_rec_t * system)
{
  if (NotZero (*system))
    {
      printf ("%-11.11s %4u %8.0f%s %5d   %4u %8.0f%s %5d\n",
	      system->System,
	      system->In.Files,
	      system->In.Bytes / BYTES_PER_KBYTE,
	      time_to_string (system->In.Time),
	      (system->In.Time ? (int) (system->In.Bytes / system->In.Time) : 0),
	      system->Out.Files,
	      system->Out.Bytes / BYTES_PER_KBYTE,
	      time_to_string (system->Out.Time),
	      (system->Out.Time ? (int) (system->Out.Bytes / system->Out.Time) : 0));
      if (do_command_report_opt && !separated_command_report_opt && system->Commands)
	{
	  puts (_("\tCommands:\n\t========="));
	  enquire_commands (system->Commands, (traverse_func_t) print_the_command);
	  puts ("");
	}
    }
}

static void
DEFUN (print_the_system_commands, (system),
       CONST system_rec_t * system)
{
  if (system->Commands)
    {
      printf ("    %s:\n", system->System);
      enquire_commands (system->Commands, (traverse_func_t) print_the_command);
      puts ("");
    }
}

static void
DEFUN_VOID (systems_report_header)
{
  puts (_("By System:\n=========="));
  puts (_("                     R E C E I V E D                       S E N T"));
  puts (_("System      Files  KBytes     Time       ATP   Files  KBytes     Time       ATP\n"));
}

void
DEFUN_VOID (systems_report)
{
  systems_report_header ();
  enquire_systems ((traverse_func_t) print_the_system);
}

void
DEFUN_VOID (systems_command_report)
{
  if (do_command_report_opt)
    {
      puts (_("\nCommands By System:\n==================="));
      enquire_systems ((traverse_func_t) print_the_system_commands);
      puts ("");
    }
}

static void
DEFUN (print_the_user, (user),
       CONST user_rec_t * user)
{
  printf ("%-11.11s  %4u  %8.0f  %s\n",
	  user->User,
	  user->Out.Files, user->Out.Bytes / BYTES_PER_KBYTE,
	  time_to_string (user->Out.Time));
  if (do_command_report_opt && !separated_command_report_opt && user->Commands)
    {
      puts (_("\tCommands:\n\t========="));
      enquire_commands (user->Commands, (traverse_func_t) print_the_command);
      puts ("");
    }
}

static void
DEFUN (print_the_user_commands, (user),
       CONST user_rec_t * user)
{
  if (user->Commands)
    {
      printf ("    %s:\n", user->User);
      enquire_commands (user->Commands, (traverse_func_t) print_the_command);
      puts ("");
    }
}

static void
DEFUN_VOID (users_report_header)
{
  puts (_("\nBy User:\n========"));
  puts (_("                        S E N T"));
  puts (_("User         Files   KBytes      Time\n"));
}

void
DEFUN_VOID (users_report)
{
  users_report_header ();
  enquire_users ((traverse_func_t) print_the_user);
}

void
DEFUN_VOID (users_command_report)
{
  if (do_command_report_opt)
    {
      puts (_("\nBy User:\n========"));
      enquire_users ((traverse_func_t) print_the_user_commands);
    }
}

static void
DEFUN (print_the_day, (day),
       CONST day_rec_t * day)
{
#if HDB_UUCP

#if TAYLOR_UUCP
  if (!is_taylor_uucp)
#endif    
    printf ("%02hd/%02hd  %4u  %8.0f  %s  %4u  %8.0f  %s\n",
	    day->Date.Month, day->Date.Day,
	    day->In.Files, day->In.Bytes / BYTES_PER_KBYTE,
	    time_to_string (day->In.Time),
	    day->Out.Files, day->Out.Bytes / BYTES_PER_KBYTE,
	    time_to_string (day->Out.Time));
#if TAYLOR_UUCP
  else
#endif

#endif /* HDB_UUCP */

#ifdef TAYLOR_UUCP
    printf ("%04hd/%02hd/%02hd  %4u  %8.0f  %s  %4u  %8.0f  %s\n",
	    day->Date.Year, day->Date.Month, day->Date.Day,
	    day->In.Files, day->In.Bytes / BYTES_PER_KBYTE,
	    time_to_string (day->In.Time),
	    day->Out.Files, day->Out.Bytes / BYTES_PER_KBYTE,
	    time_to_string (day->Out.Time));
#endif
	    
  if (do_command_report_opt && !separated_command_report_opt && day->Commands)
    {
      puts (_("\tCommands:\n\t========="));
      enquire_commands (day->Commands, (traverse_func_t) print_the_command);
      puts ("");
    }
}

static void
DEFUN (print_the_day_commands, (day),
       CONST day_rec_t * day)
{
  if (day->Commands)
    {
      printf ("    %02d/%02d:\n", day->Date.Month, day->Date.Day);
      enquire_commands (day->Commands, (traverse_func_t) print_the_command);
      puts ("");
    }
}

void
DEFUN_VOID (daily_report)
{
  puts (_("\nBy Day:\n======="));

#if HDB_UUCP

#if TAYLOR_UUCP
  if (! is_taylor_uucp)
#endif
    {
      puts (_("Date       R E C E I V E D                     S E N T"));
      puts (_("Mo/Dy  Files   KBytes       Time      Files   KBytes       Time\n"));
    }
#if TAYLOR_UUCP
  else
#endif
#endif /* HDB_UUCP */

#if TAYLOR_UUCP
    {
      puts (_("   Date         R E C E I V E D                     S E N T"));
      puts (_("Year/Mo/Dy  Files   KBytes       Time      Files   KBytes       Time\n"));
    }
#endif
  
  enquire_days ((traverse_func_t) print_the_day);
}

void
DEFUN_VOID (daily_command_report)
{
  if (do_command_report_opt)
    {
      puts (_("\nBy Day:\n======="));
      enquire_days ((traverse_func_t) print_the_day_commands);
    }
}

static void
DEFUN (print_the_system_summary, (system),
       CONST system_rec_t * system)
{
  if (NotZero (*system) || system->Calls)
    {
      printf ("\n%s:\n", system->System);
      if (NotZero (*system))
	{
	  register idx;
	  double sum_of_times, dead_time;
	  int first_rate;
	  
	  printf (_("\tReceived %10.0f (%4u Files) in %s: %4d cps\n"),
		  system->In.Bytes, system->In.Files, time_to_string (system->In.Time),
		  (system->In.Time ? (int) (system->In.Bytes / system->In.Time) : 0));
	  printf (_("\tSent     %10.0f (%4u Files) in %s: %4d cps\n"),
		  system->Out.Bytes, system->Out.Files, time_to_string (system->Out.Time),
		  (system->Out.Time ? (int) (system->Out.Bytes / system->Out.Time) : 0));
	  if (system->In.Bytes > system->Out.Bytes)
	    printf (_("\tReceived %10.0f bytes more than sent.\n"),
		    system->In.Bytes - system->Out.Bytes);
	  else if (system->In.Bytes < system->Out.Bytes)
	    printf (_("\tSent     %10.0f bytes more than received.\n"),
		    system->Out.Bytes - system->In.Bytes);
	  
	  sum_of_times = system->In.Time + system->Out.Time;
	  dead_time = system->TimeConnect - sum_of_times;
	  printf (_("\tThe system has been connected for %s"),
		  time_to_string (system->TimeConnect));
	  
	  if (dead_time && (system->TimeConnect != 0.0))
	    printf (_(" (%3.1f%% of dead time)\n"),
		    (dead_time / system->TimeConnect * 100.0));
	  else
	    puts ("");
      
	  if (system->TimePayedBy[LOCAL_SYSTEM] != 0.0 ||
	      system->TimePayedBy[REMOTE_SYSTEM] != 0.0)
	    {
	      if (system->TimePayedBy[LOCAL_SYSTEM] != 0.0)
		{
		  if (system->TimePayedBy[REMOTE_SYSTEM] == 0.0)
		    printf (_("\t\tentirely payed by the local system.\n"));
		  else
		    {
		      printf (_("\t\tof which %s (%5.1f%%) are payed by the local system\n"),
			      time_to_string (system->TimePayedBy[LOCAL_SYSTEM]),
			      system->TimePayedBy[LOCAL_SYSTEM] / system->TimeConnect * 100.0);
		      
		      printf (_("\t\t     and %s (%5.1f%%) by this system.\n"),
			      time_to_string (system->TimePayedBy[REMOTE_SYSTEM]),
			      system->TimePayedBy[REMOTE_SYSTEM] / system->TimeConnect * 100.0);
		    }
		}
	      else
		printf (_("\t\tentirely payed by this system.\n"));
	    }

	  if (pcd_names_count)
	    {
	      for (sum_of_times=0, idx = 0, first_rate=1; idx < pcd_names_count; idx++)
		sum_of_times += system->PhoneCost[idx];
	      
	      for (idx = 0, first_rate=1; idx < pcd_names_count; idx++)
		{
		  if (system->PhoneCost[idx] != .0)
		    {
		      float cost;
		      static const char * spent_text;
		      static int spent_text_len;

		      if (! spent_text)
			{
			  spent_text = _("Spent ");
			  spent_text_len = strlen (spent_text);
			}

		      cost = (pcd_rate_call_cost (idx+1) * system->PhoneCall[idx] +
			      pcd_calculate_cost (idx+1, system->PhoneCost[idx]));
		      
		      printf ("\t%*s%s (%5.1f%%",
			      spent_text_len, (first_rate ? spent_text : ""),
			      time_to_string (system->PhoneCost[idx]),
			      (system->PhoneCost[idx]/sum_of_times * 100.0));
		      if (cost)
			{
			  printf (", %*.*f %s)",
				  7+current_country.decimals,
				  current_country.decimals,
				  cost, current_country.currency);
			}
		      else
			putchar (')');

		      printf (_(" in %s\n"), pcd_rate_name (idx+1));
		      first_rate = 0;
		    }
		}
	    }
	} /* if (NotZero (*system)) */

      if (system->LastConnection)
	{
	  printf (_("\tLast connection: %s\n"), julian_to_asc (system->LastConnection));
	  
	  printf (_("\tThere have been %u call(s) (with an average of %.1f Ok/day):\n\t\t\t\t\t"),
		  system->Calls,
		  ((float) system->CallsOK / (float) DaysSinceLastClean));
	  if (system->CallsOK)
	    {
	      if (system->CallsSTOPPED)
		printf (_("%3u OK (%3u IN, %3u OUT, %3u STOPPED)\n\t\t\t\t\t"),
			system->CallsOK, system->CallsIn,
			system->CallsOut, system->CallsSTOPPED);
	      else
		printf (_("%3u OK (%3u IN, %3u OUT)\n\t\t\t\t\t"),
			system->CallsOK, system->CallsIn, system->CallsOut);
	    }
	  if (system->CallsFAIL)
	    printf (_("%3u FAILED\n"), system->CallsFAIL);
	}
      else /* system->LastConnection == 0 */
	{
	  /* This means that the system has not been contacted, due to errors
	   * so there are only failed calls */
	  printf (_("\tThere have been %u failed calls\n"), system->CallsFAIL);
	}
    }
}

static void
DEFUN_VOID (systems_summary_header)
{
  puts (_("\nSUMMARY by System:\n=================="));
}

void
DEFUN_VOID (systems_summary)
{
  systems_summary_header ();
  enquire_systems ((traverse_func_t) print_the_system_summary);
  puts ("");
}

static moved_stuff_t TotIn, TotOut;

static char *
DEFUN (bytes_to_string, (byt),
       double byt)
{
  char *stringa = (char *) malloc (11);

  sprintf (stringa, "%9.0f", byt / BYTES_PER_KBYTE);
  return stringa;
}

static void
DEFUN (print_the_system_summary_table, (sys),
       CONST system_rec_t * sys)
{
  double TotTime = sys->In.Time + sys->Out.Time;
  double TotBytes = sys->Out.Bytes + sys->In.Bytes;

  if (NotZero (*sys))
    {
      TotIn.Time += sys->In.Time;
      TotOut.Time += sys->Out.Time;
      TotIn.Bytes += sys->In.Bytes;
      TotOut.Bytes += sys->Out.Bytes;
      TotIn.Files += sys->In.Files;
      TotOut.Files += sys->Out.Files;
      printf ("|%-8.8s| %s :%10.10s: %5u | %s :%10.10s: %5u |%5d|\n",
	      sys->System,
	      bytes_to_string (sys->In.Bytes),
	      time_to_string (sys->In.Time),
	      sys->In.Files,
	      bytes_to_string (sys->Out.Bytes),
	      time_to_string (sys->Out.Time),
	      sys->Out.Files,
	      (TotTime ? (int) (TotBytes / TotTime) : 0));
    }
}

static void
DEFUN_VOID (systems_summary_table_header)
{
  puts ("+--------+------------------------------+------------------------------+-----+");
  puts (_("|        |        R E C E I V E D       |            S E N T           |     |"));
  puts (_("| SYSTEM | KiloBytes :   Time   : Files | KiloBytes :   Time   : Files | ATP |"));
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
}

void
DEFUN_VOID (systems_summary_table)
{
  systems_summary_table_header ();
  enquire_systems ((traverse_func_t) print_the_system_summary_table);
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
  printf (_("| TOTALS | %s :%10.10s: %5u | %s :%10.10s: %5u | ####|\n"),
	  bytes_to_string (TotIn.Bytes),
	  time_to_string (TotIn.Time),
	  TotIn.Files,
	  bytes_to_string (TotOut.Bytes),
	  time_to_string (TotOut.Time),
	  TotOut.Files);
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
}

static void
DEFUN (print_the_system_history_table, (sys),
       CONST system_rec_t * sys)
{
  double TotTime = sys->History.In.Time + sys->History.Out.Time + sys->In.Time + sys->Out.Time;
  double TotBytes = sys->History.Out.Bytes + sys->History.In.Bytes + sys->In.Bytes + sys->Out.Bytes;

  if (NotZero (*sys) || NotZero (sys->History))
    {
      TotIn.Time += sys->History.In.Time;
      TotOut.Time += sys->History.Out.Time;
      TotIn.Bytes += sys->History.In.Bytes;
      TotOut.Bytes += sys->History.Out.Bytes;
      TotIn.Files += sys->History.In.Files;
      TotOut.Files += sys->History.Out.Files;
      printf ("|%-8.8s| %s :%10.10s: %5u | %s :%10.10s: %5u |%5d|\n",
	      sys->System,
	      bytes_to_string (sys->History.In.Bytes + sys->In.Bytes),
	      time_to_string (sys->History.In.Time + sys->In.Time),
	      sys->History.In.Files + sys->In.Files,
	      bytes_to_string (sys->History.Out.Bytes + sys->Out.Bytes),
	      time_to_string (sys->History.Out.Time + sys->Out.Time),
	      sys->History.Out.Files + sys->Out.Files,
	      (TotTime ? (int) (TotBytes / TotTime) : 0));
    }
}

void
DEFUN_VOID (system_history_table)
{
  printf (_("\n...and since %s\n"), TheEpoc);
  puts ("+--------+------------------------------+------------------------------+-----+");
  puts (_("|        |        R E C E I V E D       |            S E N T           |     |"));
  puts (_("| SYSTEM | KiloBytes :   Time   : Files | KiloBytes :   Time   : Files | ATP |"));
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
  enquire_systems ((traverse_func_t) print_the_system_history_table);
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
  printf (_("| TOTALS | %s :%10.10s: %5u | %s :%10.10s: %5u | ####|\n"),
	  bytes_to_string (TotIn.Bytes),
	  time_to_string (TotIn.Time),
	  TotIn.Files,
	  bytes_to_string (TotOut.Bytes),
	  time_to_string (TotOut.Time),
	  TotOut.Files);
  puts ("+--------+-----------:----------:-------+-----------:----------:-------+-----|");
}

static double MonthlyActivityTotals[12];

static void
DEFUN (print_the_system_monthly_activity, (sys),
       CONST system_rec_t * sys)
{
  int idx;
  double sum = .0;

  for (idx = 0; idx <= 11; idx++)
    sum += sys->History.MonthlyActivity[idx];

  if (sum > 0.0)
    {
      printf ("\n%-6.6s", sys->System);
      for (idx = 0; idx <= 11; idx++)
	{
	  double bytes = sys->History.MonthlyActivity[(idx + CurrentMonth) % 12];

	  MonthlyActivityTotals[(idx + CurrentMonth) % 12] += bytes;
	  if (bytes == -1.0)
	    printf ("| *** ");
	  else if (bytes < 10000.0)
	    printf ("|%4.0f ", bytes);
	  else if ((bytes/BYTES_PER_KBYTE) < 10000.0)
	    printf ("|%4.0fK", bytes / BYTES_PER_KBYTE);
	  else if ((bytes/BYTES_PER_MBYTE) < 10000.0)
	    printf ("|%4.0fM", bytes / BYTES_PER_MBYTE);
	  else
	    printf ("|%4.0fG", bytes / BYTES_PER_GBYTE);
	}
    }
}

void
DEFUN_VOID (monthly_history_table)
{
  static char *MonthName[] =
  {
    "Jan", "Feb", "Mar", "Apr",
    "May", "Jun", "Jul", "Aug",
    "Sep", "Oct", "Nov", "Dec"
  };
  int idx;

  puts (_("\n\nLast 12 Months Activity\n=======================\n"));
  printf ("------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----\n");
  printf (_("System"));
  for (idx = 0; idx <= 11; idx++)
    {
      printf ("| %s", MonthName[(idx + CurrentMonth) % 12]);
      if (idx != 11)
	putchar (' ');
    }
  printf ("\n------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----");
  enquire_systems ((traverse_func_t) print_the_system_monthly_activity);
  printf ("\n------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----\n");
  printf (_("TOTALS"));
  for (idx = 0; idx <= 11; idx++)
    {
      double bytes = MonthlyActivityTotals[(idx + CurrentMonth) % 12];

      if (bytes < 0.0)
	printf ("| *** ");
      else if (bytes < 10000.0)
	printf ("|%4.0f ", bytes);
      else if ((bytes/BYTES_PER_KBYTE) < 10000.0)
	printf ("|%4.0fK", bytes / BYTES_PER_KBYTE);
      else if ((bytes/BYTES_PER_MBYTE) < 10000.0)
	printf ("|%4.0fM", bytes / BYTES_PER_MBYTE);
      else
	printf ("|%4.0fG", bytes / BYTES_PER_GBYTE);
    }
  printf ("\n------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----\n");
}

static double PortActivityTotals[TIMESLICES] = {0};

static void
DEFUN (print_the_port_activity_chart, (port),
       CONST port_rec_t * port)
{
  int row, slice;
  double maxval = 0.0;
  double scale;
  BOOLEAN IsGlobalActivityChart = (port == NULL ? TRUE : FALSE);

  for (slice = 0; slice < TIMESLICES; slice++)
    {
      double curval;

      if (!IsGlobalActivityChart)
	PortActivityTotals[slice] += (curval = port->Activity[slice]);
      else
	curval = PortActivityTotals[slice];

      if (curval > maxval)
	maxval = curval;
    }
  scale = maxval / chart_size_opt;

  if (IsGlobalActivityChart || number_of_ports() == 1)
    {
      puts (_("\n\nGlobal Hourly Activity (on a 20 minutes basis)\n=============================================="));
    }
  else
    {
      printf (_("\n\nHourly Activity (on a 20 minutes basis) on %s\n======================================================\n"), port->Port);
    }
  printf (_("Max Value :     %.0f bytes\nScale     : '#'= %.0f bytes\n\n"), maxval, scale);
  for (row = chart_size_opt; row > 0; row--)
    {
      double current_value = row * scale;

      printf ("     ");
      for (slice = 0; slice < 72; slice++)
	{
	  double curval = (IsGlobalActivityChart ?
			   PortActivityTotals[slice] : port->Activity[slice]);
	  if (curval >= current_value)
	    putchar ('#');
	  else
	    putchar (' ');
	}
      puts ("");
    }
  puts ("     ========================================================================");
  puts ("     0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23");
}

void
DEFUN_VOID (hourly_activity_charts)
{
  enquire_ports ((traverse_func_t) print_the_port_activity_chart);
  if (number_of_ports() > 1)
    print_the_port_activity_chart (0);	/* 0 means "do the global activity chart" */
}

#if USE_TCL

static char error_msg[] = "Wrong number of Parameters: %s doesn't accept any!";

int
DEFUN (tcl_systems_report, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc > 1)
    {
      sprintf (interp->result, _(error_msg), argv[0]);
      return TCL_ERROR;
    }
  systems_report ();
  return TCL_OK;
}

int
DEFUN (tcl_users_report, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc > 1)
    {
      sprintf (interp->result, _(error_msg), argv[0]);
      return TCL_ERROR;
    }
  users_report ();
  return TCL_OK;
}

int
DEFUN (tcl_daily_report, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc > 1)
    {
      sprintf (interp->result, error_msg, argv[0]);
      return TCL_ERROR;
    }
  daily_report ();
  return TCL_OK;
}

int
DEFUN (tcl_system_summary, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc > 1)
    {
      sprintf (interp->result, error_msg, argv[0]);
      return TCL_ERROR;
    }
  systems_summary ();
  return TCL_OK;
}

int
DEFUN (tcl_system_summary_table, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc > 1)
    {
      sprintf (interp->result, error_msg, argv[0]);
      return TCL_ERROR;
    }
  systems_summary_table ();
  return TCL_OK;
}

typedef enum
{
  I_DONT_KNOW = -1,
  DAILY,
  PORTS,
  SUMMARY,
  SYSTEMS,
  TABLE,
  USERS
} report_id_t;

#define NUMELEM(array) (sizeof(array) / sizeof(array[0]))

static report_id_t
DEFUN (decode_report, (report),
       char *report)

{
  register idx;
  static struct
    {
      char *report_name;
      report_id_t rep_id;
    }
  HandledRep[] =
  {
    { "daily", DAILY },
    { "ports", PORTS, },
    { "summary", SUMMARY },
    { "systems", SYSTEMS },
    { "table", TABLE },
    { "users", USERS }};

  for (idx = 0; idx < NUMELEM (HandledRep) &&
       *report >= *(HandledRep[idx].report_name); idx++)
    {
      if (*report == *(HandledRep[idx].report_name) &&
	strncmp (report, HandledRep[idx].report_name, strlen (report)) == 0)
	return HandledRep[idx].rep_id;
    }
  return I_DONT_KNOW;
}

int
DEFUN (tcl_report, (clientData, interp, argc, argv),
       ClientData clientData AND
       Tcl_Interp * interp AND
       int argc AND
       char *argv[])
{
  if (argc == 1)
    print_the_report ();
  else
    {
      report_id_t which_one;

      switch (which_one = decode_report (argv[1]))
	{
	case SUMMARY:
	  {
	    if (argc > 2)
	      {
		int idx;
		int first_time = TRUE;

		for (idx = 2; idx < argc; idx++)
		  {
		    system_rec_t *sr = search_system (argv[idx]);

		    if (sr != (system_rec_t *) NULL)
		      {
			if (first_time)
			  {
			    systems_summary_header ();
			    first_time = FALSE;
			  }
			print_the_system_summary (sr);
		      }
		    else
		      {
			sprintf (interp->result,
				 _("%s: system %s is unknown to me"),
				 argv[0], argv[idx]);
			return TCL_ERROR;
		      }
		  }
	      }
	    else
	      systems_summary ();
	  }
	  break;

	case TABLE:
	  {
	    if (argc > 2)
	      {
		int idx;
		int first_time = TRUE;

		for (idx = 2; idx < argc; idx++)
		  {
		    system_rec_t *sr = search_system (argv[idx]);

		    if (sr != (system_rec_t *) NULL)
		      {
			if (first_time)
			  {
			    systems_summary_table_header ();
			    first_time = FALSE;
			  }
			print_the_system_summary_table (sr);
		      }
		    else
		      {
			sprintf (interp->result,
				 _("%s: system %s is unknown to me"),
				 argv[0], argv[idx]);
			return TCL_ERROR;
		      }
		  }
	      }
	    else
	      systems_summary_table ();
	  }
	  break;

	case SYSTEMS:
	  {
	    if (argc > 2)
	      {
		int idx;
		int first_time = TRUE;

		for (idx = 2; idx < argc; idx++)
		  {
		    system_rec_t *sr = search_system (argv[idx]);

		    if (sr != (system_rec_t *) NULL)
		      {
			if (first_time)
			  {
			    systems_report_header ();
			    first_time = FALSE;
			  }
			print_the_system (sr);
		      }
		    else
		      {
			sprintf (interp->result,
				 _("%s: system %s is unknown to me"),
				 argv[0], argv[idx]);
			return TCL_ERROR;
		      }
		  }
	      }
	    else
	      systems_report ();
	  }
	  break;

	case USERS:
	  {
	    if (argc > 2)
	      {
		int idx;
		int first_time = TRUE;

		for (idx = 2; idx < argc; idx++)
		  {
		    user_rec_t *ur = search_user (argv[idx]);

		    if (ur != (user_rec_t *) NULL)
		      {
			if (first_time)
			  {
			    users_report_header ();
			    first_time = FALSE;
			  }
			print_the_user (ur);
		      }
		    else
		      {
			sprintf (interp->result,
				 _("%s: user %s is unknown to me"),
				 argv[0], argv[idx]);
			return TCL_ERROR;
		      }
		  }
	      }
	    else
	      users_report ();
	  }
	  break;

	case PORTS:
	  {
	    if (argc > 2)
	      {
		int idx;

		for (idx = 2; idx < argc; idx++)
		  {
		    port_rec_t *pa = search_port (argv[idx]);

		    if (pa != (port_rec_t *) NULL)
		      print_the_port_activity_chart (pa);
		    else
		      {
			sprintf (interp->result,
				 _("%s: port %s is unknown to me"),
				 argv[0], argv[idx]);
			return TCL_ERROR;
		      }
		  }
	      }
	    else
	      hourly_activity_charts ();
	  }
	  break;

	case DAILY:
	  daily_report ();
	  break;

	case I_DONT_KNOW:
	  sprintf (interp->result,
		   _("%s: Unknown report requested: I know about 'systems', 'users', 'ports' and 'daily' only"), argv[0]);
	  return TCL_ERROR;
	}
    }
  return TCL_OK;
}

#endif /* if USE_TCL */
