# include "opihi.h"

static Buffer **buffers;
static int     Nbuffers;

void InitBuffers () {
  Nbuffers = 0;
  ALLOCATE (buffers, Buffer *, 1);
}

Buffer *InitBuffer () {
  Buffer *buf;

  ALLOCATE (buf, Buffer, 1);
  bzero (buf[0].name, 1024);
  bzero (buf[0].file, 1024);
  ALLOCATE (buf[0].matrix.buffer, char, 1);
  ALLOCATE (buf[0].header.buffer, char, 1);
  return (buf);
}

int IsBuffer (char *name) {
 
  int i;

  if (name == NULL) return (FALSE);

  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
  if (i == Nbuffers) return (FALSE);
  return (TRUE);
}

int IsBufferPtr (Buffer *buf) {
 
  int i;

  if (buf == NULL) return (FALSE);

  for (i = 0; (i < Nbuffers) && (buffers[i] != buf); i++);
  if (i == Nbuffers) return (FALSE);
  return (TRUE);
}

Buffer *SelectBuffer (char *name, int mode, int verbose) {

  int i;

  if (name == NULL) goto error;
  if (ISNUM(name[0])) goto error;
  if (IsVector(name)) goto error;

  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
  /* is a new buffer */
  if (i == Nbuffers) { 
    if (mode == OLDBUFFER) goto error;
    Nbuffers += 1;
    REALLOCATE (buffers, Buffer *, Nbuffers);
    buffers[i] = InitBuffer ();
    strcpy (buffers[i][0].name, name);
    return (buffers[i]);
  } 
  /* is an old buffer */
  if (mode == NEWBUFFER) goto error;
  return (buffers[i]);

 error:
  if (verbose) fprintf (stderr, "invalid matrix %s\n", name);
  return (NULL);
}

int CreateBuffer (Buffer *buf) {

  /* store the default output values */
  buf[0].bitpix = buf[0].header.bitpix;
  buf[0].unsign = buf[0].header.unsign;
  buf[0].bzero  = buf[0].header.bzero;
  buf[0].bscale = buf[0].header.bscale;
  
  /* assign the necessary internal values */
  buf[0].header.bitpix   = -32;
  buf[0].header.unsign   = FALSE;
  buf[0].header.bzero    = 0;
  buf[0].header.bscale   = 1;
  
  /* make some test of the validity of the values */

  /* create the appropriate header and matrix */
  fits_create_header (&buf[0].header);
  fits_create_matrix (&buf[0].header, &buf[0].matrix);

  return (TRUE);
}
  
/* copy data from in to out - new memory space */
int CopyNamedBuffer (char *out, char *in) {
  Buffer *In, *Out;
  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
  CopyBuffer (Out, In);
  return (TRUE);
}

int CopyBuffer (Buffer *out, Buffer *in) {
  free (out[0].matrix.buffer);
  free (out[0].header.buffer);
  out[0].bitpix = in[0].bitpix;
  out[0].unsign = in[0].unsign;
  out[0].bscale = in[0].bscale;
  out[0].bzero  = in[0].bzero;
  strcpy (out[0].file, in[0].file);
  fits_copy_matrix (&in[0].matrix, &out[0].matrix);
  fits_copy_header (&in[0].header, &out[0].header);
  return (TRUE);
}

/* move data from in to out - use old memory space */
int MoveNamedBuffer (char *out, char *in) {
  Buffer *In, *Out;
  if ((In  = SelectBuffer (in,  OLDBUFFER, FALSE)) == NULL) return (FALSE);
  if ((Out = SelectBuffer (out, ANYBUFFER, FALSE)) == NULL) return (FALSE);
  MoveBuffer (Out, In);
  return (TRUE);
}
int MoveBuffer (Buffer *out, Buffer *in) {
  int i, j;

  free (out[0].matrix.buffer);
  free (out[0].header.buffer);
  out[0].bitpix = in[0].bitpix;
  out[0].unsign = in[0].unsign;
  out[0].bscale = in[0].bscale;
  out[0].bzero  = in[0].bzero;
  out[0].matrix = in[0].matrix;
  out[0].header = in[0].header;
  strcpy (out[0].file, in[0].file);

  /* delete buffer entry from buffer list, if it exists */
  for (i = 0; (i < Nbuffers) && (in != buffers[i]); i++);
  if (i == Nbuffers) return (TRUE);

  free (in);
  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];
  Nbuffers -= 1;
  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
  return (TRUE);
}

/* delete by ptr */
int DeleteBuffer (Buffer *buf) {

  int i, j;

  if (buf == NULL) return (FALSE);
  for (i = 0; (i < Nbuffers) && (buf != buffers[i]); i++);
  if (i == Nbuffers) return (FALSE);

  fits_free_header (&buffers[i][0].header);
  fits_free_matrix (&buffers[i][0].matrix);

  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];

  Nbuffers -= 1;
  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
  return (TRUE);
}
  
/* delete by name */
int DeleteNamedBuffer (char *name) {

  int i, j;

  if (name == NULL) return (FALSE);
  for (i = 0; (i < Nbuffers) && (strcmp(buffers[i][0].name, name)); i++);
  if (i == Nbuffers) return (FALSE);

  fits_free_header (&buffers[i][0].header);
  fits_free_matrix (&buffers[i][0].matrix);

  for (j = i; j < Nbuffers - 1; j++) buffers[j] = buffers[j + 1];

  Nbuffers -= 1;
  REALLOCATE (buffers, Buffer *, MAX (Nbuffers, 1));
  return (TRUE);
}

int SelectOverlay (char *name, int *number) {

  *number = -1;
  if (!strcmp (name, "red") || !strcmp (name, "0"))
    *number = 0;
  if (!strcmp (name, "green") || !strcmp (name, "1"))
    *number = 1;
  if (!strcmp (name, "blue") || !strcmp (name, "2"))
    *number = 2;
  if (!strcmp (name, "yellow") || !strcmp (name, "3"))
    *number = 3;

  if (*number < 0) {
    fprintf (stderr, "valid overlays may be: red (0), green (1), blue (2), yellow (3)\n");
    return (FALSE);
  }
  else {
    return (TRUE);
  }
}

void dump_buffers (int n) {

  int i;

  fprintf (stderr, "try %d\n", n);
  for (i = 0; i < Nbuffers; i++) {
    fprintf (stderr, "%d  %x\n", i, (int) buffers[i]);
    fprintf (stderr, "%d  %x  %s\n", i, (int) buffers[i][0].name, buffers[i][0].name);
    fprintf (stderr, "%d  %x  %s\n", i, (int) buffers[i][0].file, buffers[i][0].file);
    fprintf (stderr, "%d  %x  %x\n", i, (int) &buffers[i][0].header, (int) buffers[i][0].header.buffer);
    fprintf (stderr, "%d  %x  %x\n", i, (int) &buffers[i][0].matrix, (int) buffers[i][0].matrix.buffer);
    fprintf (stderr, "%d  %d  %d  %f %f\n", i, buffers[i][0].bitpix, buffers[i][0].unsign, buffers[i][0].bscale, buffers[i][0].bzero);
  }
}

int PrintBuffers (int Long) {

  int i;

  if (Nbuffers == 0) {
    fprintf (stderr, "No allocated buffers\n");
    return (TRUE);
  }
  
  if (Long) {
    fprintf (GetOutfile(), "    N       name                      file     X     Y    bytes BP  U   bzero     bscale  \n");
    for (i = 0; i < Nbuffers; i++) {
      fprintf (GetOutfile(), "%5d %10s %25s %5d %5d %10d %3d %1d %10.4e %10.4e\n",
	       i, buffers[i][0].name, buffers[i][0].file, 
	       buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
	       buffers[i][0].header.size + buffers[i][0].matrix.size, buffers[i][0].bitpix, 
	       buffers[i][0].unsign, buffers[i][0].bzero, buffers[i][0].bscale);
    }
    return (TRUE);
  }

  fprintf (GetOutfile(), "    N       name                      file     X     Y    bytes\n");
  for (i = 0; i < Nbuffers; i++) {
    fprintf (GetOutfile(), "%5d %10s %25s %5d %5d %10d\n",
	     i, buffers[i][0].name, buffers[i][0].file, 
	     buffers[i][0].header.Naxis[0], buffers[i][0].header.Naxis[1],
	     buffers[i][0].header.size + buffers[i][0].matrix.size);
  }
  return (TRUE);
}
