/**
 * \file Array.cpp
 * Implante une tableau d'enregistrements (pointeurs) supportant l'ajout mais pas la suppression.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */

#include <stdio.h>
#include <stdlib.h>

#include "Array.h"
#include "TestAlloc.h"
#include "MemoryAlloc.h"

/**
 * Constructeur pour un nouveau Array vide.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
Array::Array(void) {
  this->sz = 100;
  this->sp = 0;
  this->spt = 1;
  t =(void ***) calloc(1,sizeof(void **));
  testAllocAndExit(t,"new Array(void)");
  if ( t ) {
    t[0] =(void **) calloc(sz,sizeof(void *));
    testAllocAndExit(t[0],"new Array(void)",0); }
  nb = 0;
}

/**
 * Constructeur pour un nouveau Array vide.
 *
 * @param size La taille de bufferisation de l'objet Array.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
Array::Array(int sz) {
  this->sz = sz;
  this->sp = 0;
  this->spt = 1;
  t =(void ***) calloc(1,sizeof(void **));
  testAllocAndExit(t,"new Array(int)");
  if ( t ) {
    t[0] =(void **) calloc(sz,sizeof(void *));
    testAllocAndExit(t[0],"new Array(int)",0); }
  nb = 0;
}

/**
 * Destructeur pour un Array (sans desallocation les enregistrements qu'il contient).
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
Array::~Array(void) {
  for ( int i = 0 ; i < spt ; i++ ) {
    free(t[i]); }
  free(t);
}

/**
 * Ajout d'un enregistrement en queue d'un Array.
 *
 * @param p L'enregistrement a ajouter en queue.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Array::add(void *p) {
  if ( sp >= sz ) {
    spt++;
    sp = 0;
    t =(void ***) myRealloc(t,(spt-1)*sizeof(void **),spt*sizeof(void **));
    testAllocAndGo(t,"Array::add(void *)");
    if ( t ) {
      t[spt-1] =(void **) calloc(sz,sizeof(void *));
      testAllocAndGo(t[spt-1],"Array::add(void *)",spt-1);
      if ( t[spt-1] ) {
        t[spt-1][sp] = p; } } }
    else {
    t[spt-1][sp] = p; }
  sp++;
  nb++;
}

/**
 * Test de l'existence d'un enregistrement dans un Array.
 *
 * @param p L'enregistrement a rechercher.
 * @return 1 si l'enregistrement a ete trouve, 0 sinon.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Array::contains(void *p) {
  for ( int i = 0 ; i < spt-1 ; i++ )
    for ( int j = 0 ; j < sz ; j++ )
      if ( t[i][j] == p )
        return(1);
  for ( int j = 0 ; j < sp ; j++ )
    if ( t[spt-1][j] == p )
      return(1);
  return(0);
}

/**
 * Recherche d'un enregistrement dans un Array.
 *
 * @param index L'indice de l'enregistrement a rechercher.
 * @return Le pointeur sur l'enregistrement trouve, NULL si l'index n'existe pas.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void *Array::elementAt(int index) {
  if ( ( index < 0 ) || ( index >= nb ) )
    return(NULL);
  int pi = index/sz;
  int pj = index%sz;
  return(t[pi][pj]);
}

/**
 * Recherche de l'indice d'un enregistrement present dans un Array.
 *
 * @param p L'enregistrement rechercher.
 * @return L'indice trouve, -1 si l'enregistrement n'existe pas.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Array::indexOf(void *p) {
  int pos = 0;
  for ( int i = 0 ; i < spt-1 ; i++ )
    for ( int j = 0 ; j < sz ; j++ ) {
      if ( t[i][j] == p )
        return(pos);
      pos++; }
  for ( int j = 0 ; j < sp ; j++ ) {
    if ( t[spt-1][j] == p ) 
      return(pos);
    pos++; }
  return(-1);
}

/**
 * Retour du nombre d'enregistrements stockes dans un Array.
 *
 * @return le nombre d'enregistrements actuellement stockees
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Array::size(void) {
  return(nb);
}

/**
 * Retour d'un tableau de void * alloue dynamiquement et contenant l'ensemble des enregistrements d'un Array.
 *
 * @return le tableau des enregistrements actuellement stockes
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void **Array::getArray(void) {
  if ( nb == 0 )
    return(NULL);
  void **tp =(void **) calloc(nb,sizeof(void *));
  testAllocAndGo(tp,"Array::getArray(void)");
  if ( tp ) {
    int pos = 0;
    for ( int i = 0 ; i < spt-1 ; i++ )
      for ( int j = 0 ; j < sz ; j++ ) {
        tp[pos] = t[i][j];
        pos++; }
    for ( int j = 0 ; j < sp ; j++ ) {
      tp[pos] = t[spt-1][j];
      pos++; } }
  return(tp);
}

/**
 * Retour de la quantite de memoire utilisee pour la gestion d'un Array.
 *
 * @return la quantite de memoire.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
long Array::getUsedMemory(void) {
  return(sizeof(Array)+spt*(sizeof(void **)+sz*sizeof(void *)));
}

/**
 * Retour du nombre de handles memoires utilises pour la gestion d'un Array.
 *
 * @return le nombre de handles memoires.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Array::getUsedHandles(void) {
  return(1+1+spt);
}
