/*
 *  WMProxyPer: Window Maker dockapp that nicely displays proxyper-logfiles.
 * 
 *  Copyright (c) 1999 Wilke Havinga
 *  Thanks to Peter Brandstrom for making some improvements.
 * 
 *  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 <dockapp.h>
#include <unistd.h>
#include <stdio.h>  
#include <math.h>
#include <string.h>
 
#include "WMProxyPer_Mask.xpm"

/*#define DEBUG*/

typedef struct
{
  char type[20];	       /* Name, eg rc564/desII/ogr/csc */
  int in_current, in_max;      /* Number of keys in Inbuff/ maximum no. in inbuff */
  int out_current, out_max;    /* Number of keys in Outbuff/ maximum no. in outbuff */
  float keyrate;               /* Keyrate in KKeys*100 */
  unsigned long int totalkeys; /* Total number of keys processed by this proxy */
} logentry;

/* Some global variables that can be set using program parameters */
char *displayName = ""; /* Use default display */
char *logfilename = "/var/log/rc5.log";
int maxkeyrate = 25;  /* 2.5 MKeys/sec */
int refreshrate = 10; /* Refresh every 10 seconds */
char *workType = "rc564"; /* Default work is rc564 */

static DAProgramOption options[] = 
{
  {"-d", "--display", "Display to use [default display]", DOString, False, {&displayName} },
  {"-m", "--maxrate", "Maximum keyrate (in KKeys*100) [25]", DOInteger, False, {&maxkeyrate}},
  {"-l", "--logfile", "Logfile to read from [/var/log/rc5.log]", DOString, False, {&logfilename}},
  {"-r", "--refresh", "Refresh every x seconds [10]", DOInteger, False, {&refreshrate}},
  {"-t", "--type",    "Type of work [rc564]", DOString, False, {&workType}}
};

/*
  This function tries to read an entry from an opened logfile. It
  reads lines until it finds one that contains the workType string,
  parses it and returns a filled 'logentry'-structure. Will always
  overwrite the logentry regardless of success.

  Returns 1 if it succeeded to find and parse a workType line from the log.
  Returns 0 if it reaches EOF.  */
int
readlogentry(FILE* logfile, logentry* entry)
{
  char buffer[100];
  int fields;

  while (fgets(buffer, 100, logfile))
    {
      fields = sscanf(buffer + 18,
		 "%s r=%d/%d, d=%d/%d, %f %*s tot=%ld",
		 entry->type,
		 &entry->in_current,
		 &entry->in_max,
		 &entry->out_current,
		 &entry->out_max,
		 &entry->keyrate,
		 &entry->totalkeys);

      /* If we find 7 fields according to scanf spec and the workType
         matches we return 1, otherwise 0 */
      if (fields == 7 && strcmp(entry->type, workType) == 0)
	{
#ifdef DEBUG
	  printf("%s r=%d/%d, d=%d/%d, %f Mxxx/sec tot=%ld\n",
		 entry->type,
		 entry->in_current,
		 entry->in_max,
		 entry->out_current,
		 entry->out_max,
		 entry->keyrate,
		 entry->totalkeys);
#endif
	  return 1;
	}
    }
  return 0;
}

/*
  Opens the logfile, looks for entries regarding workType, stores the
  last macthing entry in 'entry'. If no line matches workType then we
  exit with an error.

  Returns the file handle.
*/
FILE* 
openlog(char *logfile, logentry* entry)
{
  FILE* infile = fopen(logfile, "r");
  if (infile)
    {
      logentry testEntry[2];
      int index = 0;
      int result = 1;
      int found = 0;
      
      while (result)
	{
	  result = readlogentry(infile, &testEntry[index]);
	  if (result)
	    {
	      /* Flip between two logentries so we keep the last found
                 intact */
	      index = 1 - index;
	      found = 1;
	    }
	}

      /* Did we find anything? */
      if (! found)
	{
	  fprintf(stderr,
		  "Could not find any lines containing %s. "
		  "Are you sure this is a proxyper logfile?\n",
		   workType);
	  exit(1);
	}

      /* Copy last found entry */
      memcpy(entry, &testEntry[1 - index], sizeof(logentry));
    }
  return infile;
}

void 
draw_num(GC gc, Pixmap back, Pixmap pixmap, unsigned long int num, int x, int y)
{
  static int base_x = 64, base_y = 43;
  int pos_x, pos_y, pos = 8;
  int cijfer;

  if (num == 0) /* Only display a '0' at the last position */
      XCopyArea(DADisplay, back, pixmap, gc, base_x, base_y, 5, 7, x + 2 + pos * 6, y+2);

  while (num > 0 && pos >= 0)
    {
      cijfer = num % 10;
      pos_x = x + 2 + pos * 6;
      pos_y = y + 2;
      XCopyArea(DADisplay, back, pixmap, gc, base_x + cijfer * 5, base_y, 5, 7, pos_x, pos_y);

      num = num / 10;
      pos--;
    }
}  

void 
paint(GC gc, Pixmap back, Pixmap pixmap, logentry *entry)
{
  int display_pct;
  
  XCopyArea(DADisplay, back, pixmap, gc, 0, 0, 64, 64, 0, 0);
  
  /* Draw IN-bar */
  display_pct = 43 - floor( 43 * ((float)entry->in_current / (float)entry->in_max));
  if (display_pct < 0)
    display_pct = 0;
  XCopyArea(DADisplay, back, pixmap, gc, 
	    64, display_pct, 
	    12, 43 - display_pct, 
	    3, 3 + display_pct);

  /* Draw OUT-bar */
  display_pct = 43 - floor( 43 * ((float)entry->out_current / (float)entry->out_max));
  if (display_pct < 0)
    display_pct = 0;
  
  XCopyArea(DADisplay, back, pixmap, gc, 
	    76, display_pct, 
	    12, 43 - display_pct, 
	    48, 3 + display_pct);

  /* Draw KEYRATE-bar */
  display_pct = 43 - floor(43 * (entry->keyrate*10 /(float)maxkeyrate));
  if (display_pct < 0)
    display_pct = 0;
  
  XCopyArea(DADisplay, back, pixmap, gc, 
	    88, display_pct, 
	    28, 43 - display_pct, 
	    19, 3 + display_pct);
  
  /* Draw TOTAL_KEYS line */
  draw_num(gc, back, pixmap, entry->totalkeys, 3, 49);
  
  DASetPixmap(pixmap);
}

int
main (int argc, char **argv)
{
  FILE* logfile;
  GC gc;
  Pixmap pixmap, back, mask;
  logentry entry;
  
  static unsigned int d_width = 128;
  static unsigned int d_height = 64;
  
  DAInitialize (displayName, "WMProxyPer", 64, 64, argc, argv);
  gc = DefaultGC(DADisplay, DefaultScreen(DADisplay));
  DAParseArguments(argc, argv, options, 
		   sizeof(options)/sizeof(DAProgramOption), 
		   "WMProxyPer", "WMProxyPer 0.9");
  if (maxkeyrate < 1) /* Of course a zero maximum keyrate is not what you want */
    maxkeyrate = 1;   /* (Insert personal nightmare about dividing by zero here) */
  if (refreshrate < 1) /* Don't allow 'constant updates', as it will take *much* CPU time */
    refreshrate = 1;
    
  DAMakePixmapFromData(WMProxyPer_Mask_xpm, &back, &mask, &d_width, &d_height);
  DASetShape(mask);
  pixmap = DAMakePixmap();
  DAShow();
  if (!(logfile = openlog(logfilename, &entry)))
    {
      fprintf (stderr, "Could not open file (%s)!\n", logfilename);
      exit (1);
    }

  paint(gc, back, pixmap, &entry);
  
  while (1) 
    {
      XEvent ev;
      
      if (readlogentry(logfile, &entry) == 1)
	paint(gc, back, pixmap, &entry);
      while (XPending(DADisplay))
	{
	  XNextEvent(DADisplay, &ev);
	  DAProcessEvent(&ev);
	}
      usleep(refreshrate * 1000000); /* Wait 'refreshrate' seconds */
    }
  fclose(logfile);
}
