/* account.c 
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "account.h"

#ifndef MAP_FILE
#define MAP_FILE
#endif

int fdin; // The file descriptor of the memory-mapped file

/* The content of an array of accounts is stored in ascii form in filedat, one record per line.
   If the file filebin exists, it contains the same array in binary form.
   If the file filebin does not exist, it is created. 
   In either case the file filebin is memory mapped into an array and the address of the array is
   returned. The number of records in array is returned through the pointer size.
   WARNING: Because of my laziness, this function does not return the file descriptor
   of the binary file. Hence this file will be closed only when the program terminates.
 */
account_t *readin_accounts ( const char * filedat, const char * filebin, int *size )
{
  FILE *fin;
  int k;
  account_t *accounts;
  account_t * p;
  int total_size;
  int binfile_exists;
  
  fdin = open(filebin, O_RDWR);
  binfile_exists = (fdin >= 0);
  if (!binfile_exists) {
    printf ("The binary file does not exist\n");
    
    fin = fopen(filedat, "r");
    if (fin < 0) {
      perror("fopen");
      exit(0);
    }
    fscanf (fin, "%d", size);
    printf("The size is %d\n", *size);
    total_size = (*size)*sizeof(account_t);

    umask(0);
    fdin = open(filebin, O_RDWR | O_CREAT | O_TRUNC);
    if (fdin < 0) {
      perror ("open");
      exit (1);
    } 
    lseek (fdin, total_size - 1, SEEK_SET);
    write (fdin, " ", 1);
  } else {
    struct stat statbuf;
    
    printf ("The binary file exists\n");
    if (fstat(fdin, &statbuf) < 0) {
      perror ("fstat");
      exit(1);
    }
    total_size = statbuf.st_size;
    *size = total_size/sizeof(account_t);
  }

  accounts = (struct account *) mmap(0, total_size, PROT_WRITE,
				     MAP_FILE | MAP_SHARED, fdin, 0);
  if (accounts == (struct account *)MAP_FAILED) {
    perror("mmap");
    exit(0);
  }
  
  if (!binfile_exists) {
    p = accounts;
    for (k=0; (k < (*size)) && (!feof(fin)); ++k ) {
      fscanf(fin, "%s %d", &(p->id), &(p->balance));
      printf("\t%s\t%d\n", p->id, p->balance);
      ++p;
    }
    fclose(fin);
  }
  return accounts;
}

/* Write out accounts */
void write_accounts(const char * filename, int size, const account_t *accounts)
{
  FILE *fin;
  int k;
  account_t * p;
  fin = fopen(filename, "w");

  for (k = 0; k < size; ++k, accounts++)
    fprintf(fin, "%s  %d\n", accounts->id, accounts->balance);
  fclose(fin);
}




