#include <stdio.h>
#include <fcntl.h>

typedef int INTUSED;

int hoffd = -1;
#define BUFFER_SIZE 5000000
INTUSED hofq[BUFFER_SIZE];

int main(argc, argv) 
  unsigned int argc; char **argv; {
  INTUSED n, n_wanted;
  off_t file_size;
  char *filename;

  /* parse command line */
  if (argc != 3) {
    fputs("Usage: hof n filename\n", stderr);
    exit(1);
    }
  n_wanted = atoi(argv[1]);
  filename = argv[2];

  hoffd = open(filename, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
  if (hoffd < 0) {
    perror("Could not create data file");
    exit(1);
    }
  file_size = lseek(hoffd, 0, SEEK_END);
  if (file_size == -1) {
    perror("Could not measure size of data file");
    exit(1);
    }
  n = file_size/sizeof(INTUSED);
  if (n > 2) {
    int rc;
    rc = lseek(hoffd, 0, SEEK_SET);
    if (rc == -1) {
      perror("Could not rewind data file");
      exit(1);
      }
    rc = read(hoffd, &hofq, sizeof(hofq));
    if (rc == -1) {
      perror("Could not initialise from data file");
      exit(1);
      }
    }
  else {
    setq(1, 1);
    setq(2, 1);
    n = 3;
    }
  /* TODO: should check to see if any previous data is left over */
  for (; n<=n_wanted; n++) {
    /* q[n] = q[n - q[n-1]] + q[n - q[n-2]]; */
    INTUSED q = getq(n-getq(n-1))+getq(n-getq(n-2));
    if (q <= 0 || q > n) {
      fprintf(stderr, "panic at n=%d, q=%d\n", n, q);
      exit(1);
      }
    setq(n, q);
/*
    if (0 == (n % 1000)) {
      printf("%d %d\r", n, q);
      }
*/
    }
  close(hoffd);
  exit(0);
  }

INTUSED getq(n)
  INTUSED n;
  {
  if (n < BUFFER_SIZE) {
    return hofq[n];
    }
  else {
    INTUSED q;
    int rc = lseek(hoffd, n*sizeof(INTUSED), SEEK_SET);
    if (rc < 0) {
      perror("lseek failed");
      exit(1);
      }
    rc = read(hoffd, &q, sizeof(INTUSED));
    if (rc < 0) {
      perror("read failed");
      exit(1);
      }
    return q;
    }
  }

int setq(n, q) 
  INTUSED n;
  INTUSED q;
  {
  int rc = lseek(hoffd, n*sizeof(INTUSED), SEEK_SET);
  if (rc < 0) {
    perror("lseek failed");
    exit(1);
    }
  if (n < BUFFER_SIZE) {
    hofq[n] = q;
    }
  write(hoffd, &q, sizeof(INTUSED));
  }


