static char rcsid[] = "$Id$";
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "spliceendsgen.h"
#include <stdio.h>
#include <stdlib.h>
#include "assert.h"
#include "mem.h"

/* Used to keep a pool of allocated Spliceends_T objects, which are
   used for recursive calls to extend the ends of extend the starts or
   ends of an alignment, and thereby reduce the number of allocations
   and frees for each thread. */


#define T Spliceendsgen_T
struct T {
  int nallocated;
  int ncheckedout;
  List_T pool;
};


T
Spliceendsgen_new () {
  T new = (T) MALLOC_KEEP(sizeof(*new));

  new->nallocated = 0;
  new->ncheckedout = 0;
  new->pool = (List_T) NULL;

  return new;
}


void
Spliceendsgen_reset (T this) {
  this->nallocated = 0;
  this->ncheckedout = 0;
  this->pool = (List_T) NULL;
  return;
}


void
Spliceendsgen_free_memory (T this) {
  Spliceends_T item;
  List_T p;

  assert(this->ncheckedout == 0);

  for (p = this->pool; p != NULL; p = List_next(p)) {
    item = (Spliceends_T) List_head(p);
    Spliceends_free(&item);
  }
  List_free_keep(&this->pool);

  return;
}


void
Spliceendsgen_free (T *old) {
  FREE_KEEP(*old);
  return;
}


/* Use instad of Spliceends_new */
Spliceends_T
Spliceendsgen_checkout (T this, int querylength) {
  Spliceends_T new, old;
  List_T p;

  if (this->ncheckedout == this->nallocated) {
    new = Spliceends_new(/*id*/this->nallocated++,querylength); /* Already in checkedout state */
    this->pool = List_push_keep(this->pool,(void *) new);
    this->ncheckedout++;
    return new;

  } else {
    for (p = this->pool; p != NULL; p = List_next(p)) {
      old = (Spliceends_T) List_head(p);
      if (old->checkedout_p == false) {
	old->checkedout_p = true;
	this->ncheckedout++;
	return old;
      }
    }

    fprintf(stderr,"Problem with Spliceendsgen_checkout: %d checked out, %d allocated, but cannot find it\n",
	    this->ncheckedout,this->nallocated);
    abort();
    return (Spliceends_T) NULL;
  }
}


/* Use instead of Spliceends_free */
void
Spliceendsgen_return (T this, Spliceends_T *old) {
  Spliceends_T item;
  List_T p;

  if (*old) {
    for (p = this->pool; p != NULL; p = List_next(p)) {
      item = (Spliceends_T) List_head(p);
      if (item == *old) {
	(*old)->checkedout_p = false;
	this->ncheckedout--;
	return;
      }
    }

    fprintf(stderr,"Problem with Spliceendsgen_return: but cannot find spliceends %p returned\n",
	    *old);
    abort();
  }

  return;
}
    
