#include <vo_stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <vstypes.h>
#include <vsrv.h>
#include <audio.h>
#include <timers.h>
#include <crc32.h>
#include <apploader.h>
#include <kernel.h>


#define MIN(a,b) (((a)<(b))?(a):(b))


#define MAX_N 8

u_int16 buf[256];

DLLEXPORT(CalcCrc32File);
DLLEXPORT(ReturnHexadecimalValueFFD2);
DLLEXPORT(DoesnTExist);

ioresult CalcCrc32File(register char *fileName, register u_int16 verbose,
		       register s_int16 times) {
  ioresult ret = S_ERROR;
  FILE *fp = fopen(fileName, "rb");
  u_int32 bytes = 0, bytesLeft = 0;
  u_int32 crc32[MAX_N] = {0}, crcTime[MAX_N] = {0};
  u_int32 startTime, totTime, lastTime;
  int i;

  if (times < 0 || times > MAX_N) {
    goto finally;
  }

  if (!fp) {
    printf("E: File \"%s\" not found\n", fileName);
    goto finally;
  }

  
  bytes = bytesLeft = fp->fileSize;
  printf("BYTES    0x%08lx = %ld\n", bytes, bytes);

  startTime = lastTime = ReadTimeCount();

  while (bytesLeft > 1) {
    u_int16 toRead = (u_int16)MIN(bytesLeft, 512) >> 1;
    if (fread(buf, 1, toRead, fp) != toRead) {
      printf("E: Read error @ 0x%lx/0x%lx\n", ftell(fp), bytes);
      goto finally;
    }
    lastTime = ReadTimeCount();
    for (i=0; i<times; i++) {
      u_int32 nowTime;
      crc32[i] = CalcCrc32(crc32[i], buf, 2*toRead);
      nowTime = ReadTimeCount();
      crcTime[i] += nowTime-lastTime;
      lastTime = nowTime;
    }
    bytesLeft -= 2*toRead;
  }
  if (bytesLeft) {
    char c = fgetc(fp);
    for (i=0; i<times; i++) {
      crc32[i] = CalcCrc32Byte(crc32[i], c);
    }
  }

  totTime = ReadTimeCount() - startTime;
  if (!totTime) totTime++;

  for (i=0; i<times; i++) {
    printf("CRC32[%d] 0x%08lx (est. %6.3f s, %5u KB/s\n",
	   i, crc32[i], 0.001*crcTime[i], (int)(bytes/crcTime[i]));
  }
  if (verbose) {
    printf("TIME     %.3f s\n", 0.001*totTime);
    printf("SPEED    %d KB/s\n", (int)(bytes/totTime));
  }
  ret = S_OK;

 finally:
  if (fp) {
    fclose(fp);
    fp = NULL;
  }
  return ret;
}

u_int16 ReturnHexadecimalValueFFD2(void) {
  return 0xFFD2;
}

ioresult main(char *parameters) {
  int nParam, i;
  char *p = parameters;
  ioresult ret = S_ERROR;
  int verbose = 1, times = 1;

  nParam = RunProgram("ParamSpl", parameters);
  for (i=0; i<nParam; i++) {
    if (!strcmp(p, "-h")) {
      printf("Usage: Crc32 [-v|+v|-i|+i|-xn|-h] file1 [...]\n"
	     "-v|+v\tVerbose on|off\n"
	     "-i|+i\tIgnore CRC32 calculation on|off\n"
	     "-xn\tCalculate CRC32 n times, allowed range is 0...%d\n"
	     "-h\tShow this help\n", MAX_N);
      ret = S_OK;
      goto finally;
    } else if (!strcmp(p, "-v")) {
      verbose = 1;
    } else if (!strcmp(p, "+v")) {
      verbose = 0;
    } else if (!strcmp(p, "-i")) {
      times = 0;
    } else if (!strcmp(p, "+i")) {
      times = 1;
    } else if (!strncmp(p, "-x", 2)) {
      times = (int)(strtol(p+2, NULL, 0));
      if (times < 0 || times > MAX_N) {
	printf("E: Illegal value for parameter \"%s\"\n", p);
	goto finally;
      }
    } else {
      if (CalcCrc32File(p, verbose, times)) {
	goto finally;
      }
    }
    p += strlen(p)+1;
  }

  ret = S_OK;

  ReturnHexadecimalValueFFD2();
  
 finally:
  return ret;
}
