# include "opihi.h"

static Vector **vectors;
static int     Nvectors;
  
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// this function is NOT thread protected : it is only used in startup and/or shutdown
void InitVectors () {
  Nvectors = 0;
  ALLOCATE (vectors, Vector *, 1);
}

// this function is NOT thread protected : it is only used in startup and/or shutdown
void FreeVectors () {

  int i;

  for (i = 0; i < Nvectors; i++) {
    free (vectors[i][0].elements);
    free (vectors[i]);
  }
  free (vectors);
}

Vector *InitVector () {
  Vector *vec;

  ALLOCATE (vec, Vector, 1);
  ALLOCATE (vec[0].elements, float, 1);
  bzero (vec[0].name, 1024);
  vec[0].Nelements = 0;
  return (vec);
}

int IsVector (char *name) {
 
  int i;

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

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

int IsVectorPtr (Vector *vec) {
 
  int i;

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

  for (i = 0; (i < Nvectors) && (vectors[i] != vec); i++);
  if (i == Nvectors) return (FALSE);
  return (TRUE);
}

Vector *SelectVector (char *name, int mode, int verbose) {

  int i;

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

  for (i = 0; (i < Nvectors) && (strcmp(vectors[i][0].name, name)); i++);
  /* is a new vector */
  if (i == Nvectors) { 
    if (mode == OLDVECTOR) goto error;
    pthread_mutex_lock (&mutex);
    Nvectors ++;
    REALLOCATE (vectors, Vector *, Nvectors);
    vectors[i] = InitVector ();
    strcpy (vectors[i][0].name, name);
    pthread_mutex_unlock (&mutex);
    return (vectors[i]);
  } 
  /* is an old vector */
  if (mode == NEWVECTOR) goto error;
  return (vectors[i]);

 error:
  if (verbose) gprint (GP_ERR, "invalid vector %s\n", name);
  return (NULL);
}
  
/* delete by pointer */
int DeleteVector (Vector *vec) {

  int i, j;

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

  for (i = 0; (i < Nvectors) && (vec != vectors[i]); i++);
  if (i == Nvectors) return (FALSE);

  free (vectors[i][0].elements);
  free (vectors[i]);

  pthread_mutex_lock (&mutex);
  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
  Nvectors --;
  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
  pthread_mutex_unlock (&mutex);
  return (TRUE);
}
  
/* delete by name */
int DeleteNamedVector (char *name) {

  int i, j;

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

  free (vectors[i][0].elements);
  free (vectors[i]);

  pthread_mutex_lock (&mutex);
  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
  Nvectors --;
  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
  pthread_mutex_unlock (&mutex);
  return (TRUE);
}

/* copy data from in to out - new memory space */
int CopyNamedVector (char *out, char *in) {
  Vector *In, *Out;
  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
  CopyVector (Out, In);
  return (TRUE);
}
int CopyVector (Vector *out, Vector *in) {
  free (out[0].elements);
  out[0].Nelements = in[0].Nelements;
  ALLOCATE (out[0].elements, float, out[0].Nelements);
  memcpy (out[0].elements, in[0].elements, out[0].Nelements*sizeof(float));
  return (TRUE);
}

/* move data from in to out - use old memory space */
int MoveNamedVector (char *out, char *in) {
  Vector *In, *Out;
  if ((In  = SelectVector (in,  OLDVECTOR, FALSE)) == NULL) return (FALSE);
  if ((Out = SelectVector (out, ANYVECTOR, FALSE)) == NULL) return (FALSE);
  MoveVector (Out, In);
  return (TRUE);
}
int MoveVector (Vector *out, Vector *in) {
  int i, j;

  free (out[0].elements);
  out[0].Nelements = in[0].Nelements;
  out[0].elements =  in[0].elements;

  /* delete vector entry from vector list, if it exists */
  for (i = 0; (i < Nvectors) && (in != vectors[i]); i++);
  if (i == Nvectors) {
    free (in);
    return (TRUE);
  }

  pthread_mutex_lock (&mutex);
  for (j = i; j < Nvectors - 1; j++) vectors[j] = vectors[j + 1];
  Nvectors --;
  REALLOCATE (vectors, Vector *, MAX (Nvectors, 1));
  free (in);
  pthread_mutex_unlock (&mutex);
  return (TRUE);
}

int ListVectors () {

  int i;

  if (Nvectors == 0) {
    gprint (GP_ERR, "No defined vectors\n");
    return (FALSE);
  }

  gprint (GP_LOG, "    N       name      size\n");
  for (i = 0; i < Nvectors; i++) {
    gprint (GP_LOG, "%5d %10s %10d\n",
	     i, vectors[i][0].name, vectors[i][0].Nelements);
  }
  return (TRUE);
}
  
