/**
 * \file Vector.cpp
 * Implante une structure de stockage d'un vecteur d'adresses memoire.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */

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

#include "Vector.h"

static void freeListe(int taille,struct Vector::liste *racine);

int Vector::cpt = 0;

/**
 * Constructeur pour un nouveau Vector vide.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
Vector::Vector(void) {
  taille = 0;
  racine = NULL;
  fin = NULL;
  cpt++;
}

/**
 * Destructeur pour un Vector (sans desallocation les enregistrements qu'il contient).
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
Vector::~Vector(void) {
  freeListe(taille,racine);
  cpt--;
}

/**
 * Ajout d'un enregistrement en queue d'un Vector.
 *
 * @param p L'enregistrement a ajouter en queue.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Vector::add(void *p) {
  taille++;
  struct liste *l =(struct liste *) calloc(1,sizeof(struct liste));
  l->suiv = NULL;
  l->p = p;
  if ( racine == NULL ) {
    racine = l;
    fin = l; }
    else {
    fin->suiv = l;
    fin = l; }
}

/**
 * Insertion d'un enregistrement dans un Vector.
 *
 * @param index L'indice de la position d'insertion
 * @param p L'enregistrement a ajouter.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Vector::add(int index,void *p) {
  if ( ( index < 0 ) || ( index > taille ) )
    return;
  taille++;
  struct liste *l =(struct liste *) calloc(1,sizeof(struct liste));
  l->p = p;
  if ( racine == NULL ) {
    racine = l;
    fin = l;
    return; }
  if ( index == taille-1 ) {
    fin->suiv = l;
    fin = l;
    return; }
  if ( index == 0 ) {
    l->suiv = racine;
    racine = l;
    return; }
  struct liste *a = racine;
  int i = 1;
  while ( i < index ) {
    a = a->suiv;
    i++; }
  l->suiv = a->suiv;
  a->suiv = l;
}

/**
 * Test de l'existence d'un enregistrement dans un Vector.
 *
 * @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 Vector::contains(void *p) {
  struct liste *l = racine;
  while ( ( l != NULL ) && ( l->p != p ) ) {
    l = l->suiv; }
  if ( l == NULL )
    return(0);
  return(1);
}

/**
 * Recherche d'un enregistrement dans un Vector.
 *
 * @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 *Vector::elementAt(int index) {
  if ( ( index < 0 ) || ( index >= taille ) )
    return(NULL);
  if ( racine == NULL )
    return(NULL);
  struct liste *l = racine;
  int i = 0;
  while ( i < index ) {
    l = l->suiv;
    i++; }
  return(l->p);
}

/**
 * Recherche de l'indice d'un enregistrement present dans un Vector.
 *
 * @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 Vector::indexOf(void *p) {
  struct liste *l = racine;
  int i = 0; 
  while ( ( l != NULL ) && ( l->p != p ) ) {
    i++;
    l = l->suiv; }
  if ( l == NULL )
    return(i);
  return(-1);
}

/**
 * Retrait d'un enregistrement d'un Vector.
 *
 * @param index l'indice de l'enregistrement retire
 * @return l'enregistrement retire, NULL si elle n'existe pas
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void *Vector::remove(int index) {
  if ( ( index < 0 ) || ( index >= taille ) )
    return(NULL);
  if ( racine == NULL )
    return(NULL);
  if ( index == 0 ) {
    struct liste *l = racine;
    taille--;
    racine = racine->suiv;
    if ( taille == 0 )
      fin = NULL;
    void *p = l->p;
    free(l);
    return(p); }
  struct liste *l = racine->suiv;
  struct liste *a = racine;
  int i = 1;
  while ( i < index ) {
    a = l;
    l = l->suiv;
    i++; }
  void *p = l->p;
  if ( l == fin )
    fin = a;
  a->suiv = l->suiv;
  taille--;
  free(l);
  return(p);
}

/**
 * Retrait d'un enregistrement d'un Vector.
 *
 * @param p l'enregistrement a retirer
 * @return 1 si l'enregistrement a ete trouve et retire, 0 sinon
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Vector::remove(void *p) {
  if ( racine == NULL )
    return(0);
  if ( racine->p == p ) {
    struct liste *l = racine;
    taille--;
    racine = racine->suiv;
    if ( taille == 0 )
      fin = NULL;
    free(l);
    return(1); }
  struct liste *l = racine->suiv;
  struct liste *a = racine;
  while ( ( l != NULL ) && ( l->p != p ) ) {
    a = l;
    l = l->suiv; }
  if ( l == NULL )
    return(0);
  if ( l == fin )
    fin = a;
  a->suiv = l->suiv;
  taille--;
  free(l);
  return(1);
}

/**
 * Retrait d'un enregistrement d'un Vector.
 *
 * @param index l'indice de l'enregistrement retire
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Vector::removeElementAt(int index) {
  if ( ( index < 0 ) || ( index >= taille ) )
    return;
  if ( racine == NULL )
    return;
  if ( index == 0 ) {
    struct liste *l = racine;
    taille--;
    racine = racine->suiv;
    free(l);
    return; }
  struct liste *l = racine->suiv;
  struct liste *a = racine;
  int i = 1;
  while ( i < index ) {
    a = l;
    l = l->suiv;
    i++; }
  if ( l == fin )
    fin = a;
  a->suiv = l->suiv;
  taille--;
  free(l);
  return;
}

///
/// Retour du dernier element du Vector.
///
/// @return Le dernier element.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 01/01/10
///
void *Vector::lastElement(void) {
  if ( fin )
    return(fin->p);
  return(NULL);
}

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

static void freeListe(int taille,struct Vector::liste *racine) {
  if ( taille != 0 ) {
    void **t =(void **) calloc(taille,sizeof(void *));
    struct Vector::liste *l = racine;
    for ( int i = 0 ; i < taille ; i++ ) {
      t[i] = l;
      l = l->suiv; }
    for ( int i = 0 ; i < taille ; i++ ) {
      free(t[i]); }
    free(t); }
}

/**
 * Vidage d'un Vector sans desallocation de ses enregistrements.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Vector::removeAll(void) {
  freeListe(taille,racine);
  taille = 0;
  racine = NULL;
  fin = NULL;
}

/**
 * Vidage d'un Vector et desallocation (free) de l'ensemble des enregistrements qu'il contient.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void Vector::fullFree(void) {
  void **t =(void **) calloc(taille,sizeof(void *));
  struct liste *l = racine;
  for ( int i = 0 ; i < taille ; i++ ) {
    t[i] = l;
    l = l->suiv; }
  for ( int i = 0 ; i < taille ; i++ ) {
    free(((struct liste *) t[i])->p);
    free(t[i]); }
  free(t);
  taille = 0;
  racine = NULL;
  fin = NULL;
}

/**
 * Vidage un Vector et delete de l'ensemble des enregistrements qu'il contient.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
/*void Vector::fullDelete(void) {
  void **t =(void **) calloc(taille,sizeof(void *));
  struct liste *l = racine;
  for ( int i = 0 ; i < taille ; i++ ) {
    t[i] = l;
    l = l->suiv; }
  for ( int i = 0 ; i < taille ; i++ ) {
    delete(((struct liste *) t[i])->p);
    free(t[i]); }
  free(t);
  taille = 0;
  racine = NULL;
  fin = NULL;
}*/

/**
 * Retour d'un tableau de void * alloue dynamiquement et contenant l'ensemble des enregistrements d'un Vector.
 *
 * @return le tableau des enregistrements actuellement stockes
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void **Vector::getArray(void) {
  if ( taille == 0 )
    return(NULL);
  void **t =(void **) calloc(taille,sizeof(void *));
  struct liste *l = racine;
  for ( int i = 0 ; i < taille ; i++ ) {
    t[i] = l->p;
    l = l->suiv; }
  return(t);
}

/**
 * Retour de la taille d'un Vector.
 *
 * @return la taille.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int Vector::tailleVector(void) {
  struct liste *l = racine;
  int nb = 0;
  while ( l ) {
    nb++;
    l = l->suiv; }
  return(nb);
}

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

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