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


#define TAILLE_TAB  100 /* Taille max du tableau contenant les allocations*/
#define NB_ALLOCS 15 /*nombre d'allocations automatiques (doit être inferieur a TAILLE_TAB)*/

static void*  tab[TAILLE_TAB]; /* Tableau contenant les adresses des blocs alloués */
static int nbAlloc=0,echec=0,reussi=0, taille_tas;

// Procédure pour allouer/desallouer aléatoirement NB_MANIP fois
void automatique() {
	
	int i,aleatoire,taille_restant=taille_tas;
	
	// Allocations/desallocations aléatoires ..
	srandom(getpid());
	for(i=0;i<NB_ALLOCS;i++) {
		// Si on dépasse la taille du tableau
		if ( nbAlloc>TAILLE_TAB-1 ) {
			puts("Attention, le nombre max d'allocations autorisées dans ce test est dépassé.");
			return;
		}
		
		// myMalloc
		if ( (random()%3) > 0) {
			// Taille aléatoire :
			aleatoire=random()%(taille_restant/3);
			
			// Si le pointeur renvoyé par myMalloc est nul, c'est un échec
			if( (tab[nbAlloc]=myMalloc(aleatoire)) == NULL ) {
				echec++;
			} 
			// Sinon
			else {
				// Pour que le fonctionnement aléatoire soit meilleur (= que l'on ait pas de trop grande valeur) :
				taille_restant -= aleatoire;
				// Mise à jour des variables
				nbAlloc++;
				reussi++;
				
				#ifdef DEBUG
					affichage();
				#endif
			}
		}
		// myFree
		else {
			// Si il n'y aucun bloc occupé, on ne peut pas faire de 'free' ...
			if ( nbAlloc > 0 ) {
				aleatoire=random()%nbAlloc;
				if ( myFree(tab[aleatoire]) == 0 ) {
					tab[aleatoire]=tab[nbAlloc-1];
					nbAlloc--;
					#ifdef DEBUG
						affichage();
					#endif
				}
			} else {
				// Etant donné que l'on a rien fait, on décrément le compteur
				i--;
			}
		}
	}
	
	printf("\nIl y'a eu %d allocations effectuées et %d réussies\n",echec+reussi,reussi);
	
	// On retourne au menu
	menu();
	
}	
// Procédure qui demande à l'utilisateur les informations pour allouer, et qui alloue.
void allouer(){
	
	int size;
	printf("\n-------=={ ALLOUER }==-------\n\nQuelle est la taille de du bloc a allouer (en octets) :\n--> ");                                          
	if (scanf("%d",&size) != 1) {
		printf("Veuillez rentrer un nombre (positif) ..");
		return;
	}		
	
	tab[nbAlloc]=myMalloc(size);
	if( tab[nbAlloc] == NULL ) {
		puts("    !!!! Echec de l'allocation !!!!");
		echec++;
	} else {
		nbAlloc++;
		reussi++;
	}
}

// Procédure qui demande à l'utilisateur les informations pour libérer un bloc, et qui le libère.   
void liberer(){

	printf("\n-------=={ LIBERER }==-------\n\nAdresses des blocs alloués :\n");
	int i;
	for (i = 0 ; i<nbAlloc ; i++) {
		printf(" - blocs %d : %d \n",i, tab[i]);
	}
	
	int choix; 
	printf("\nEntrez le n° du bloc à supprimer :\n--> ");
	if (scanf("%d",&choix) != 1 && choix >=0 && choix <nbAlloc) {
		puts("Veuillez rentrer un des nombres qui est dans la liste ci-dessus ..");
		return;
	}
	
	myFree(tab[choix]);
    
	// Mise à jour de 'tab' :
	if (nbAlloc-1 != choix ) {
		tab[choix]=tab[nbAlloc-1];
	}
	nbAlloc--;
	
}
     
	
// Le Menu interactif :
int menu(){
	
	int rep2;
	
	while ( 1 ) {
		// Question à poser à l'utilisateur :
		printf("\n\n-------=={ MENU }==-------\nVoulez vous\n - 1) allouer\n - 2) desallouer\n - 3) allocations/desallocations automatiques\n - 4) affichage du tas\n - 5) quitter\n--> ");
		scanf("%d",&rep2);
		
		switch(rep2){
				
			//alloquer
			case 1:
				allouer();
				break ; 
					
			//libérer
			case 2:
				liberer();
				break ;
				
			//allocations/desallocations automatiques   
			case 3:
				automatique();
				break; 
			
			//affichage     
			case 4:
				affichage();
				break; 
			
			//quitter 		
			case 5:
				printf("\nIl y'a eu %d allocations effectuées et %d réussies\n",echec+reussi,reussi);
				puts("\n\n	Au Revoir.  :)\n");
				exit(0);
				break;
			
			default:
				break;
		}
		printf("\nIl y'a eu %d allocations effectuées et %d réussies\n",echec+reussi,reussi);
	}
}
     

int main(int argc, char *argv[]){
	
	// Gestion des arguments
	if ( argc == 2 ) {
		taille_tas=atoi(argv[1]);
		if ( taille_tas<= MAX_SIZE && taille_tas > EN_TETE) {
			printf("\nLe tas va être initialisé a : %d Octets\n",taille_tas);
			preallocate(taille_tas);
		} else {
			printf("\n\nErreur : La taille que vous avez specifié est trop petite (<= %d) ou superieur à la taille maximum d'un tas qui est de %d octets.\n\n	-- Veuillez relancer le programme avec une valeur adéquat --\n\n",EN_TETE,MAX_SIZE);
			exit(1);
		}
	} else{
		printf("Quelle taille souhaitez vous affecter au 'tas' (en octets)?\n--> ");
		scanf("%d",&taille_tas);
                preallocate(taille_tas);
	}
	
	// Lance le Menu
	menu();
	
	return 0;
}
