/* dynVector.c */
/* Win2000, cygwin/gcc */

#include "dynVector.h"
#include <stdio.h>


/* Allocate memory for a dynamic vector whose totalSize is 0.
 * params:
 *   int slotSize         amount of bytes which makes up a slot
 *   int slotIncr         amount of slots dynamically added if we
 *                         have run out of storage
 * returns:
 *   DynVector *          pointer to created vector
 */
DynVector *createDynVector(int slotSize, int slotIncr) {
  DynVector *dv = (DynVector *)malloc(sizeof(DynVector));
  if (!dv) {
    onErrorOutOfMemory();
  }
  dv->slotSize = slotSize;
  dv->totalSize = 0;
  dv->nextSlot = 0;
  dv->storage = NULL;
  dv->slotIncr = slotIncr;
  return dv;
}



/* Add an element to the vector.
 * params:
 *   DynVector *dv        pointer to vector of interest
 *   void *element        pointer to element of interest
 * returns:
 *   void *               NULL if adding not successful: the old
 *                         situation is preserved; not NULL if
 *                         successful
 */
void *addElDynVector(DynVector *dv, void *element) {
  if (!dv) {
    onNullPointer();
    return NULL;
  }
  if (dv->nextSlot * dv->slotSize == dv->totalSize) {
    int newSize = (dv->slotIncr * dv->slotSize) + dv->totalSize;
    unsigned char *tmpP = (unsigned char *)realloc(dv->storage, newSize);
    if (!tmpP) {
      onErrorOutOfMemory();
      return tmpP;
    }
    dv->totalSize = newSize;
    dv->storage = tmpP;
  }
  memcpy(dv->storage + dv->nextSlot * dv->slotSize, element, dv->slotSize);
  dv->nextSlot++;
  return dv->storage;
}



/* Get pointer to element at the specified index.
 * params:
 *   DynVector *dv        pointer to vector of interest
 *   int slotIndex        slot index or element index
 * returns:
 *   void *               NULL if out of range or if NULL slot;
 *                         pointer to element otherwise
 */
void *getElPtrDynVector(DynVector *dv, int slotIndex) {
  if (!dv) {
    onNullPointer();
    return NULL;
  }
  if (slotIndex >= dv->nextSlot) {
    return NULL;
  }
  return dv->storage + (slotIndex * dv->slotSize);
}


/* Get number of elements in vector.
 * params:
 *   DynVector *dv        pointer to vector of interest
 * returns:
 *   int                  number of elements or -1 if dv is NULL
 */
int getSizeDynVector(DynVector *dv) {
  if (!dv) {
    onNullPointer();
    return -1;
  }
  return dv->nextSlot;
}


/* Free all memory in possession of the vector.
 * params:
 *   DynVector *dv        pointer to vector of interest
 * returns:
 *   void                 --
 */
void deleteDynVector(DynVector *dv) {
  if (!dv) {
    onNullPointer();
    return;
  }
  free(dv->storage);
  free(dv);
}



/* Print the vector
 * params:
 *   DynVector *dv        pointer to vector of interest
 *   int slotIndex        index to vector element of interest
 *   void (*fp)()         pointer to function printing
 *                         the element.
 * returns:
 *   void                 --
 */
void printDynVector(DynVector *dv, int slotIndex, void (*fp)()) {
  if (!dv) {
    onNullPointer();
    return;
  }
  printf("DynVector:\n");
  printf("  slotSize: %d\n", dv->slotSize);
  printf("  totalSize: %d\n", dv->totalSize);
  printf("  nextSlot: %d\n", dv->nextSlot);
  printf("  storage: %d\n", dv->storage);
  printf("  slotIncr: %d\n", dv->slotIncr);

  if (fp) {
    fp(dv->storage + (slotIndex * dv->slotSize));
    puts("");
  }
}
