# include <ohana.h>
# define DTIME(A,B) ((A.tv_sec - B.tv_sec) + 1e-6*(A.tv_usec - B.tv_usec))

# define LCK_ACCESS  1   /* can't get access to file */
# define LCK_TIMEOUT 2   /* timeout setting lock */
# define LCK_HARDLCK 3   /* error setting hard lockfile */
# define LCK_HUNLOCK 4   /* error clearing hard lockfile */

# define LCK_EMPTY   5   /* locked file is empty */
# define LCK_FULL    6   /* locked file is not empty */
# define LCK_UNKNOWN 7   /* can't stat file to get size */

# define LCK_SOFT    10  /* soft lock */
# define LCK_HARD    11  /* hard lock */
# define LCK_XCLD    12  /* exclusive soft lock */

int clearlockfile2 (char *filename, int fd, int hard, int *state);
int setlockfile2 (char *filename, double timeout, int hard, int *state);

static char dbfile[] = "/h/eugene/kiawe/test.db";

void main (int argc, char **argv) {

  char buffer[10000], hostname[1025];
  int vbuffer[10000];
  FILE *f;
  int i, j, Nrun, status, fd, pid, Remote;
  int dbstate;
  struct timeval now, then;  
  double dtime;
  
  /* check cmd line args */
  if (argc > 1) {
    if (!strcmp (argv[1], "-check")) {
      f = fopen (dbfile, "r");
      if (f == (FILE *) NULL) {
	fprintf (stderr, "ERROR: can't open file\n");
	exit (0);
      }
      status = fread (buffer, 1, 5000, f);
      if (status != 5000) {
	fprintf (stderr, "ERROR: can't read header\n");
	exit (0);
      }
      sscanf (&buffer[500], "%*s %*s %*s %d", &Nrun);
      for (j = 0 ; j < Nrun; j++) {
	status = fread (vbuffer, 4, 1000, f);
	if (status != 1000) {
	  fprintf (stderr, "ERROR: can't read data\n");
	  exit (0);
	}
	for (i = 0; i < 1000; i++) {
	  if (vbuffer[i] != j) {
	    fprintf (stderr, "ERROR: invalid data %d/%d,  %d - %d\n", j, Nrun, i, vbuffer[i]);
	    exit (0);
	  }
	}
      }
      fprintf (stderr, "Data is good, %d entries\n", Nrun);
      exit (0);
    }
  }	  

  /* set hard lock on dbfile */
  if ((fd = setlockfile2 (dbfile, 60.0, LCK_HARD, &dbstate)) == -1) {
    fprintf (stderr, "ERROR: can't set lock on %s, state is %d\n", dbfile, dbstate);
    exit (1);
  }

  /* setlock will return an fd to an open file ready for read/write access */

  /* first pass test, use only fd */
  /* read the header block, change one line, write the header block */
  /* write a block to EOF */

  /* for new file, create header block with value of 0 */
  if (dbstate == LCK_EMPTY) {
    for (i = 0; i < 50; i++) {
      memset (&buffer[100*i], 65+i, 99);
      buffer[100*i + 99] = '\n';
    }
    sprintf (&buffer[500], "THIS IS TEST    0   \n");
    Nrun = 0;
  } else {
    status = read (fd, buffer, 5000);
    /* status = fread (buffer, 1, 5000, f); */
    if (status != 5000) {
      fprintf (stderr, "ERROR: can't read data\n");
      exit (0);
    }
    /* check on current number of entries */
    sscanf (&buffer[500], "%*s %*s %*s %d", &Nrun);
    Nrun ++;
    sprintf (&buffer[500], "THIS IS TEST    %d   \n", Nrun);
  }


# define STREAMS 1

  /* position to begining of file to write header */
# if (STREAMS)
  f = fdopen (fd, "r+"); 

  if (Nrun == 20) {
    freopen (f, 
  fseek (f, 0, SEEK_SET);
  status = fwrite (buffer, 1, 5000, f);
# else 
  lseek (fd, 0, SEEK_SET);
  status = write (fd, buffer, 5000);
# endif

  if (status != 5000) {
    fprintf (stderr, "ERROR: failed writing data to header\n");
    exit (0);
  }

  for (i = 0; i < 1000; i++) vbuffer[i] = Nrun;

# if (STREAMS)
  fseek (f, 0, SEEK_END);
  status = fwrite (vbuffer, 1, 4000, f);
# else 
  lseek (fd, 0, SEEK_END);
  status = write (fd, vbuffer, 4000);
# endif

  if (status != 4000) {
    fprintf (stderr, "ERROR: failed writing data to file\n");
    exit (0);
  }

  clearlockfile2 (dbfile, fd, LCK_HARD, &dbstate);
# if (STREAMS)
  fclose (f);
# else 
  close (fd);
# endif


}

