/*
 * simpleapi.c:
 * 
 * This is a simple UNIX I/O style interface to the SIO LLAPI calls.
 * 
 * 
 */

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "sio_fs.h"
/* #include "interval-cache.h" */
#include "simpleapi.h"

#define SIMPLEAPI_DEBUG  1

ARRAYLIST_INIT(openfile_list,simplefile_infop);



void _delete_siofd(siofd)
     int siofd;
{
 int num;
 simplefile_infop p;

 ARRAYLIST_LOOKUP(openfile_list,siofd,siofd,num);
 ARRAYLIST_DELETE(openfile_list,num,p);
 free(p);
 return;
}

simplefile_infop _lookup_siofd(extfd) 
     int extfd;
{
  int ret;
  ARRAYLIST_LOOKUP(openfile_list,extfd,extfd,ret);
  if (ret < 0) { return NULL; }
  return(openfile_list[ret]);
}

void _insert_siofd(siofd,extfd,name)
    int siofd, extfd;
    char *name;
{
  simplefile_infop p;
  
  p = (simplefile_infop) malloc(sizeof (struct simplefile_info));
  assert(p);
 
  p->extfd=extfd;
  p->siofd=siofd;
  strcpy(p->filename,name);

  /* HACK FOR MESSKIT HF  -- enable caching for one file only */
  /*  if (extfd == 3) { 
    p->cached=1;
   interval_cache_init(siofd);
    create_thread(driver);
   printf("created driver\n");

  } else {
   */
  p->cached=0;
  p->offset=0;
  p->maxbyteaccessed=0;
  ARRAYLIST_ADD(openfile_list,p);
}

void simplecloseanddelete_(unit)
 int *unit;
{
  int siofd;
  sio_return_t status;
  simplefile_infop p;
  p = _lookup_siofd(*unit);
  if (!p) { fprintf(stderr, "simpleapi error\n"); return; }
  siofd = p->siofd;

   if (p->cached) { /* flush cache */
     /*      ic_operation(0, p->maxbyteaccessed, IC_SYNC, 1, NULL);*/
   }

  status =  sio_close(siofd);  
  sio_unlink(p->filename);
   _delete_siofd(siofd);
}


void simpleopen_(name, unit, mode)
char *name;
long *unit;
long *mode;
{
 sio_return_t status;
 int fd, siomode;
 simplefile_infop p;
 int i,l;

 /* first fix non null-terminated name if necessary */

 l = strlen(name);
 for(i=0; i < l; i++) {
   if (!isalnum(name[i]) && name[i] != '.' && name[i] != '/'  ) { 
     fprintf(stderr, "simpleopen: strange character in name (%c)\n", name[i]);
     name[i]='\0'; break; 
   }
 }

 fprintf(stderr, "simpleopen: opening file %s\n", name);
 /* parse mode, set up SIO modes */

 switch(*mode) {
 case 0: 
   siomode = SIO_MODE_READ|SIO_MODE_WRITE;
   break;
 case 1:
   fprintf(stderr, "simpleopen: warning -- possibly deleting existing file %s\n", name);
   sio_unlink(name);
   siomode = SIO_MODE_WRITE|SIO_MODE_CREATE;
   break;
 case 2: /* unknown */
   fprintf(stderr, "simpleopen: warning -- possibly deleting existing file %s\n", name);
   sio_unlink(name);
   siomode = SIO_MODE_WRITE|SIO_MODE_READ|SIO_MODE_CREATE;
   break;
 case 3: /* scratch unknown  -- don't delete though */
   siomode = SIO_MODE_WRITE|SIO_MODE_READ;
   break;
 default:
   fprintf(stderr, "simpleopen: unknown mode %d\n", *mode);
   siomode = SIO_MODE_READ;
   break;
 }

 status = sio_open(&fd,        /* file id */
          (char *)name,        /* file name */
          siomode,             /* file mode */
          0,                   /* control ops */
          0);                  /* control ops count */
         
 if (status != SIO_SUCCESS) {
   if (*mode != 3 ) {
     fprintf(stderr, "sio_open: %s\n", sio_error_string(status));
     return;
   } else {  /* retry with create flag */
     siomode = siomode|SIO_MODE_CREATE;
     status = sio_open(&fd,        /* file id */
		     (char *)name,        /* file name */
		     siomode,             /* file mode */
		     0,                   /* control ops */
		     0);                  /* control ops count */
     if (status != SIO_SUCCESS) {
       fprintf(stderr, "sio_open: %s\n", sio_error_string(status));
       return;
     }
   }
 }
 fprintf(stderr, "simpleopen: opening %s\n", name);
 _insert_siofd(fd, *unit, name);

}


void simpleunlink_(name)
char *name;
{
  sio_unlink(name);
}

void simpleunlink(name)
char *name;
{
  fprintf(stderr, "simpleopen: deleting file %s\n", name);
  sio_unlink(name);
}


int simpleopen(name, mode)
char *name;
int mode;
{
 sio_return_t status;
 int siofd, siomode;

 /* parse mode, set up SIO modes */

 switch(mode) {
 case 0: 
   siomode = SIO_MODE_READ;
   break;
 case 1:
   siomode = SIO_MODE_WRITE|SIO_MODE_CREATE;
   break;
 default:
   fprintf(stderr, "simpleopen: unknown mode %d\n", mode);
   siomode = SIO_MODE_READ;
   break;
 }

 status = sio_open(&siofd,      /* file id */
          name,                 /* file name */
          siomode,              /* file mode */
          0,                    /* control ops */
          0);                   /* control ops count */
         
 if (status != SIO_SUCCESS) {
    fprintf(stderr, "sio_open: %s\n", sio_error_string(status));
    return(-1);
 }

 

 _insert_siofd(siofd,siofd,name);

 return(siofd);

}


void simpleclose(fd)
int fd;
{
   int siofd;
   sio_return_t status;
   simplefile_infop p;
   p = _lookup_siofd(fd);
   siofd = p->siofd;

   if (p->cached) { /* flush cache */
     /*      ic_operation(0, p->maxbyteaccessed, IC_SYNC, 1, NULL); */
   }

   status =  sio_close(siofd);
   _delete_siofd(siofd);
}

void simpleclose_(unit)
int *unit;
{
  fprintf(stderr, "simpleclose: closing unit %d\n", *unit);
  simpleclose(*unit);
}

void simpleseek(fd, offset, whence)
int fd;
int offset;
int whence;
{
  int siofd;
  simplefile_infop p;


  p = _lookup_siofd(fd);
  siofd = p->siofd;

  switch(whence){
  case 0:
     p->offset = offset;
     break;
  case 1:
     p->offset += offset;     
     break;
  case 2:
     fprintf(stderr, "simpleseek: SEEK_END not implemented");
     break;
  }
}


void simpleseek_(unit, offset, whence)
int *unit;
int *offset;
int *whence;
{
  simpleseek(*unit, *offset, *whence);
}



void simplerewind(fd)
int fd;
{
  int siofd;
  simplefile_infop p;

  p = _lookup_siofd(fd);

  siofd = p->siofd;
  p->offset=0;

}

void simplerewind_(unit)
int *unit;
{
  int fd;
  simplefile_infop p;

  p = _lookup_siofd(*unit);
  if (!p) { fprintf(stderr, "simpleapi error\n"); return; }

  fd = p->siofd;
  p->offset =0;
}


void simplewrite(fd,buffer,nbytes)
int fd;
char *buffer;
int nbytes;
{
 sio_file_io_list_t fl;
 sio_mem_io_list_t ml;
 sio_transfer_len_t total =0;
 int siofd;
 sio_return_t status;
 simplefile_infop p;

 p = _lookup_siofd(fd);
 siofd =  p->siofd;

 fl.offset = p->offset;
 fl.size =  nbytes;
 fl.stride = 0;
 fl.element_cnt = 1;

 ml.size = nbytes;
 ml.stride = 0;
 ml.element_cnt = 1;
 ml.addr = buffer;

#if SIMPLEAPI_DEBUG > 0
 fprintf(stderr, "simplewrite: issuing write (off=%d, size=%d)\n",
	p->offset, nbytes);
#endif

 status= sio_sg_write(siofd,   /* file descriptor */
             &fl,     /* file list */
             1,       /* file list length */
             &ml,     /* memory list */
             1,       /* memory list length */
             &total); /* total bytes transferred */

 if (status != SIO_SUCCESS) {
    fprintf(stderr, "simplewrite: %s\n", sio_error_string(status));
    return;
 }

 p->offset += total;
 if (p->maxbyteaccessed < p->offset) {
   p->maxbyteaccessed =  p->offset;
 }
}

void simplewrite_(buffer,unit,nbytes)
char *buffer;
int *unit;
int *nbytes;
{
 sio_file_io_list_t fl;
 sio_mem_io_list_t ml;
 sio_transfer_len_t total =0;
 int fd;
 sio_return_t status;
 simplefile_infop p;

 p = _lookup_siofd(*unit);
  if (!p) { fprintf(stderr, "simpleapi error\n"); return; }
 fd =  p->siofd;


 if (p->cached) {
   /*   total= ic_operation(p->offset, *nbytes, IC_WRITE, 1,  (unsigned char *)buffer);*/
 } else {

   fl.offset = p->offset;
   fl.size = *nbytes;
   fl.stride = 0;
   fl.element_cnt = 1;

   ml.size = *nbytes;
   ml.stride = 0;
   ml.element_cnt = 1;
   ml.addr = (char *)buffer;

#if 0
   fprintf(stderr, "simplewrite: issuing write (off=%d, size=%d)\n",
	fl.offset, fl.size);
#endif

   status= sio_sg_write(fd,   /* file descriptor */
			&fl,     /* file list */
			1,       /* file list length */
			&ml,     /* memory list */
			1,       /* memory list length */
			&total); /* total bytes transferred */

   if (status != SIO_SUCCESS) {
     fprintf(stderr, "simplewrite: %s\n", sio_error_string(status));
     return;
   }
 }

 p->offset += (int) total;
 if (p->maxbyteaccessed < p->offset) {
   p->maxbyteaccessed =  p->offset;
 }
}

void simpleread(fd,buffer,nbytes)
int fd;
char *buffer;
int nbytes;
{
 sio_file_io_list_t fl;
 sio_mem_io_list_t ml;
 sio_transfer_len_t total =0;
 int siofd;
 sio_return_t status;

 simplefile_infop p;

 p = _lookup_siofd(fd);
 siofd =  p->siofd;

 fl.offset = p->offset;
 fl.size = nbytes;
 fl.stride = 0;
 fl.element_cnt = 1;

 ml.size = nbytes;
 ml.stride = 0;
 ml.element_cnt = 1;
 ml.addr = buffer;

#if SIMPLEAPI_DEBUG > 0
 fprintf(stderr, "simpleread: issuing read (off=%d, size=%d)\n",
	 fl.offset, fl.size);
#endif

 status = sio_sg_read(siofd,   /* file descriptor */
             &fl,     /* file list */
             1,       /* file list length */
             &ml,     /* memory list */
             1,       /* memory list length */
             &total); /* total bytes transferred */

 if (status != SIO_SUCCESS) {
    fprintf(stderr, "simpleread: %s\n", sio_error_string(status));
    return;
 }

 p->offset += total;
 if (p->maxbyteaccessed < p->offset) {
   p->maxbyteaccessed =  p->offset;
 }
}


void simpleread_(buffer,unit,nbytes)
char *buffer;
int *unit;
int *nbytes;
{
 sio_file_io_list_t fl;
 sio_mem_io_list_t ml;
 sio_transfer_len_t total =0;
 sio_return_t status;
 simplefile_infop p;

 int fd;

 p = _lookup_siofd(*unit);
  if (!p) { fprintf(stderr, "simpleapi error\n"); return; }
 fd =  p->siofd;

 if (p->cached) {
   /*   total= ic_operation(p->offset, *nbytes, IC_READ, 1, (unsigned char *)buffer);*/
 } else {

   fl.offset = p->offset;
   fl.size = *nbytes;
   fl.stride = 0;
   fl.element_cnt = 1;

   ml.size = *nbytes;
   ml.stride = 0;
   ml.element_cnt = 1;
   ml.addr = (char *)buffer;

#if 0 
   fprintf(stderr, "simpleread: issuing read (off=%d, size=%d)\n",
	   fl.offset, fl.size);
#endif
   status = sio_sg_read(fd,      /* file descriptor */
			&fl,     /* file list */
			1,       /* file list length */
			&ml,     /* memory list */
			1,       /* memory list length */
			&total); /* total bytes transferred */

   if (status != SIO_SUCCESS) {
     fprintf(stderr, "simpleread: %s\n", sio_error_string(status));
     return;
   }
 }
 p->offset += total;
 if (p->maxbyteaccessed < p->offset) {
   p->maxbyteaccessed =  p->offset;
 }
}


