/* gdwcount
   S. J. Melhuish
   Fri 02nd April 1999
*/

#define PROG_VERSION "0.20"

/* Use gd routines to make a simple web counter */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#ifndef LINUX
  #include "kernel.h"

  #include "gd.h" /* gd lib */
  #include "gdfontmb.h" /* gd small font */
  static _kernel_osfile_block inout ;
#else
  #include <gd.h>
  #include <gdfontmb.h>
#endif

#define MARGIN_X 5
#define MARGIN_Y 2
#define MAX_VALUES 32
#define BUFFSIZE 512
#define FONT gdFontMediumBold

static gdImagePtr im_out ; /* The png file as a gd image */
static int bg, fg ;
static char *outname ;
static int values[MAX_VALUES] ;
static char line_buf[BUFFSIZE] ;

static void write_png(void)
{
  /* Open png file for o/p and get GD to write it */

  FILE *out ;

  out = fopen(outname, "wb");
  /* Write png */
  if (!out)
  {
    /* Report _this_ error to stderr! */
    fprintf(stderr, "Could not create output file.\n") ;
    exit(0) ;
  }

  gdImagePng(im_out, out);
  fclose(out);
  #ifndef linux
    inout.load = 0xb60 ; /* Filetype for png */
    /* settype */
    _kernel_osfile(18, outname, &inout) ;
  #endif
  /* forget image */
  gdImageDestroy(im_out);
}

static void allocate_colours(int bgc, int fgc)
{
  /* First color allocated is background. */
  unsigned char
    red[] = {0xff, 0xdd, 0xba, 0x99, 0x77, 0x55, 0x33, 0x00,
             0x00, 0xee, 0x00, 0xdd, 0xee, 0x55, 0xff, 0x00},
    grn[] = {0xff, 0xdd, 0xba, 0x99, 0x77, 0x55, 0x33, 0x00,
             0x44, 0xee, 0xcc, 0x00, 0xee, 0x88, 0xba, 0xba},
    blu[] = {0xff, 0xdd, 0xba, 0x99, 0x77, 0x55, 0x33, 0x00,
             0x99, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0xff} ;

  bgc %= 16 ;
  fgc %= 16 ;

  bg = gdImageColorAllocate(im_out, red[bgc], grn[bgc], blu[bgc]) ;
  fg = gdImageColorAllocate(im_out, red[fgc], grn[fgc], blu[fgc]) ;
}

static void get_value(char *string, int i, int *values)
{
  /* Try to read a value from string, delimited by ',' or '\n'
     We start just after the previous ','
  */

  char *endp ;

  values[i] = (int) strtol(string, &endp, 10) ; /* string to int */
}

static int read_line(FILE *fp, int *values)
{
  /* Read a line from the log file
     Save any read values into values
     Ditto for flags (indicate if a value is missing)
     line is the line number
     Save the time to time */

  int i, count = 0 ;
  char *next ;

  /* Set defaults */

  for (i=0; i<MAX_VALUES; values[i++] = 0) ;

  /* Read the next line */

  if (!fgets(line_buf, BUFFSIZE, fp)) return 0 ;

  next = line_buf ; /* Start looking for commas on the line */

  while ((next = strchr(next, ',')) && (count < MAX_VALUES))
  {
    ++next  ; /* Value comes after comma */
    get_value(next, count, values) ; /* Read it */
    ++count ; /* No. values found */
  }

  /* Run out of values */

  return 1 ;
}

static int write_line(FILE *fp, int *values)
{
  /* Write all the latest values to the log */

  int i ;
  time_t t ;

  time(&t) ; /* Get time */
  /* Write GMT tp log */
  strftime(line_buf, BUFFSIZE, "%d/%m/%Y %H:%M:%S", gmtime(&t)) ;

  fputs(line_buf, fp) ;

  /* Print all channel values */
  for (i=0; i<MAX_VALUES; ++i) {
    if (values[i] > 0) fprintf(fp, ", %d", values[i]) ;
    else fprintf(fp, ", ") ;
  }

  /* End with newline */
  fprintf(fp, "\n") ;

  return 1 ;
}

static void find_last_line(FILE *fp)
{
  /* Find the start of the last line in file
     by search for next to last newline */

  int offset = -2 ; /* CHaracter before last */

  while (!fseek(fp, offset, SEEK_END))
  {
    int c ;

    --offset ;

    c = fgetc(fp) ;
    if (c == EOF) return ;

    if (c == '\n') return ;
  }

  /* Dodginess - just rewind */
  rewind(fp) ;
}

int main(int argc, char *argv[])
{
  int width = 50, height = 20, ch, fgc = 0 /* White */, bgc = 7 /* Black */ ;
  char buf[20] ;
  FILE *in ;

  if ((argc != 4) && (argc != 6)){
    fprintf(stderr, "gdwcount version %s\nDr. Simon J. Melhuish\n\
simon@melhuish.net\n", PROG_VERSION) ;
    fprintf(stderr, "Usage: gdwcount in_file out_file column [bgcolour fgcolour].\n") ;
    exit(0) ;
  }

  width = 2*MARGIN_X + 6*FONT->w ;
  height = 2*MARGIN_Y + FONT->h ;

  outname = argv[2] ;
  ch = atoi(argv[3]) ;
  if (argc == 6) { /* Colour numbers supplied */
    bgc = atoi(argv[4]) ;
    fgc = atoi(argv[5]) ;
  }

  im_out = gdImageCreate(width, height) ;
  if (!im_out) exit(0) ; /* Just die */

  /* Set up all the colours we will need */
  allocate_colours(bgc, fgc) ;

  in = fopen(argv[1], "r") ;
  if (!in) exit(0) ;

  find_last_line(in) ;

  read_line(in, values) ;
  fclose(in) ;

  ++values[ch] ;

  /* Write the count */
  sprintf(buf, "%06d", values[ch]) ;
  gdImageString(im_out, FONT,
    MARGIN_X, MARGIN_Y, (unsigned char *) buf, fg) ;

  write_png() ;

  /* Append new log entries */

  in = fopen(argv[1], "a") ;
  if (in) {
    write_line(in, values) ; /* Update log */
    fclose(in) ;
  }

  return 0 ;
}

