#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H

#ifdef UNIX
# include <stdio.h>
# include <malloc.h>
#else
# include <stdlib.h>
#endif

#include <mbari/types.h>
#include <mbari/const.h>
#include <mbari/param.h>

/*
CLASS 
DynamicArray

DESCRIPTION
This class is an array of void pointers which grows to accomodate
new elements.

This class is a work-around for the sad, sad, fact that VxWorks
does not currently support templates.

AUTHOR
Tom O'Reilly
*/
class DynamicArray {

  public:
  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] incr: Number of elements to increment with each realloc
  // of array space.
  DynamicArray(int incr = 10) {

    if (incr <= 0)    
    {
      mem_error = TRUE;
      return;
    }
    n_elems = 0;
    n_allocd = 0;
    alloc_incr = incr;
  }

  ///////////////////////////////////////////////////////////////////
  // Destructor
  ~DynamicArray() {
    if (n_allocd)
      free(array);
  }

  ///////////////////////////////////////////////////////////////////
  // Set specified element to specified value
  int set(int i, void **val)
  {
    if (i < 0)
    {
      mem_error = TRUE;
      return -1;
    }

    if (i >= n_allocd)
    {
      // Compute blocks needed to index specified element
      int nblocks = (i + 1) / alloc_incr;
      if ((i+1) % alloc_incr)
        nblocks++;

      if (!n_allocd)
      {
        n_allocd = nblocks * alloc_incr;
        if ((array = (void **)malloc(n_allocd*sizeof(void *))) == 0)
        {
          mem_error = TRUE;
          return -1;
        }
      }
      else
      {
        n_allocd += (nblocks * alloc_incr);
        if ((array = (void **)realloc(array, n_allocd*sizeof(void *))) == 0)
        {
          mem_error = TRUE;
          return -1;
        }
      }
    }
    array[i] = *val;
    mem_error = FALSE;
    n_elems = MAX((i+1), n_elems);
    return 0;
  }

  ///////////////////////////////////////////////////////////////////
  // Get value of specified element
  int get(int i, void **val)
  {
    if (i < 0 || i >= n_elems)
    {
      mem_error = TRUE;
      return -1;
    }
    *val = array[i];
    mem_error = FALSE;
    return 0;
  }

  ///////////////////////////////////////////////////////////////////
  // Return number of elements in array
  int size() 
  {
    return n_elems;
  }
  
  int get_n_elems() { return n_elems; }
  int get_n_allocd() { return n_allocd; }
  void **get_array() { return array; }

  ///////////////////////////////////////////////////////////////////
  // Add element to array
  int add(void **val)
  { 
    return set(size(), val);
  }
  
  ///////////////////////////////////////////////////////////////////
  // Remove all elements from array
  void clear()
  {
    n_elems = 0;
  }
  
  ///////////////////////////////////////////////////////////////////
  // Check for memory allocation error
  MBool mem_error;
 
  private:
  void **array;
  int n_elems;
  int n_allocd;

  // Size of malloc'ed and realloc'ed blocks (in # elems)
  int alloc_incr;

};


#endif
