/*

 _           _
(_)_ __   __| | _____  __
| | '_ \ / _` |/ _ \ \/ /
| | | | | (_| |  __/>  <
|_|_| |_|\__,_|\___/_/\_\


AUTEUR	: Aymeric & Samira
GROUPE	: 5 (RT)
DATE	: 02/04/2003
FICHIER	: index.cpp


*/


#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
#include <string.h>
#include "index.h"


// ---------------------------------------------------------------- //
// ------------------------- CONSTRUCTEUR ------------------------- //
// ---------------------------------------------------------------- //

INDEX::INDEX()
{
	int i=0;

	// on declare le tableau dynamique contenant les index avec la
	// valeur max definie dans fiche.cpp
	int max=F.retourneMax();

	// on a max+1 car on doit prendre en compte le premier enregistrement
	// des index qui situe une case liberee
	listeindex=new INFO_INDEX [max+1];

	// ouverture du flux vers le fichier en lecture
	// les index sont lus dans le fichier index.dat
	fstream f("index.dat",ios::in);

	// on verifie l'existence du fichier
	if (!f)
	{

		// si le fichier n'existe pas on cree une nouvelle base de donnees
		cout << "\nCreation d'une nouvelle base de donnees ....\n";

		// creation du premier index
		strcpy(listeindex[i].cle,"tetechainage");

		// la premiere chaine est mise a -1 pour signaler qu'il n'y a encore aucun element
		listeindex[i].chaine=-1;
		
		// on met le nombre d'element a 1
		nb_elt=1;
	}
	else
	{
		// sinon on recopie tous les elements dans le tableau listeindex[]
		char tempocle[32];
		int tempochaine;

		cout << "\nChargement de la base de donnees ....\n";

		// on se place au debut du fichier pour lire les informations
		f.seekg(ios::beg);
		do
		{
			f >> tempocle >> tempochaine;
			if (strcmp(tempocle,"") != 0)
			{
				strcpy(listeindex[i].cle,tempocle);
				listeindex[i].chaine=tempochaine;
				i++;
			}
		}
		while (!f.eof());
		nb_elt=i;
	}

	if ((nb_elt-1) == 0) cout << "0 fiche trouvee...\n";
	else cout << nb_elt-1 << " fiches trouvees...\n";
	
	f.close();

}


// ---------------------------------------------------------------- //
// ------------------------- DESTRUCTEUR -------------------------- //
// ---------------------------------------------------------------- //


INDEX::~INDEX()
{
	// on ouvre le flux en direction du fichier index.dat en ecriture
	fstream f("index.dat",ios::out);

	// on se place au debut du fichier
	f.seekp(ios::beg);

	// on copie tout notre tableau dans le fichier
	for (int i=0; i < nb_elt; i++)
	{
		f << listeindex[i].cle << " " << listeindex[i].chaine << endl;
	}
	f.close();

	cout << "\nEnregistrement de la base de donnees ...\n";
	if ((nb_elt-1) == 0) cout << "0 fiche enregistree...\n";
	else cout << nb_elt-1 << " fiches enregistrees...\n";

	cout << endl;
	// on efface le tableau
	delete []listeindex;
}


// ---------------------------------------------------------------- //
// -------------------------- FONCTIONS --------------------------- //
// ---------------------------------------------------------------- //


// cette fonction permet l'ajout d'un index et appelle la fonction
// d'ajout d'une fiche
void INDEX::ajoute()
{
	// on verifie que la memoire n'est pas pleine
	int max=F.retourneMax();

	if (nb_elt > max)
	{
		cout << "\n/!\\ Memoire pleine !\n";
		return;
	}

	char tempocle[32];
	int position;

	// on demande de rentrer le nom de la personne
	// le nom servira de cle a l'index
	do
	{
		cout << "\n\nRentrez le nom : ";
		cin >> tempocle;

		// on cherche la position ou placer le nouvel index
		position=cherchePosition(tempocle,nb_elt,true);

		// tant qu'on rentre un nom qui existe deja on demande d'en rentrer un nouveau
		if (position == 0) cout << "\nCette cle est deja presente ! Veuillez rentrer un autre nom !\n";
	}
	while (position == 0);

	// on ajoute la fiche
	// cette fonction nous retourne la prochaine case libre
	int chaine=F.ajoute(tempocle,listeindex[0].chaine);

	// si la prochaine case est egale au max on previent
	if (chaine == max)
	{
		cout << "\n/!\\ Attention memoire pleine ! Nous avons atteint " << max << " fiches !\n";
	}
	else
	{
		// sinon on insere la nouvelle cle
		if (listeindex[0].chaine == -1) listeindex[0].chaine=0;
		
		insereCle(tempocle,listeindex[0].chaine,position);

		//on met a jour la tete de chaine
		listeindex[0].chaine=chaine;

		// on increment le nombre d'elements
		nb_elt++;
	}
}


// cette fonction permet de supprimer un index
void INDEX::supprime()
{
	char tempocle[32];
	cout << "\n\nRentrez le nom : ";
	cin >> tempocle;

	// on determine ou se trouve l'element a supprimer
	int position=retournePosition(tempocle,nb_elt);
	
	// position == -1 si l'element n'existe pas
	if (position == -1) cout << "\n=> Element introuvable";
	else
	{
		// on supprime la fiche associee
		F.supprime(position,listeindex[0].chaine);

		// on met a jour la tete de chaine
		listeindex[0].chaine=position;

		// on decale les index
		decaleIndex(cherchePosition(tempocle,nb_elt,false));

		// on decremente le nombre d'element
		nb_elt--;
		
		cout << "\nSuppression de " << tempocle << " reussie avec succes !";
	}

	cout << "\n\nAppuyez sur ENTREE pour continuer";
	getchar();
}


// cette fonction permet de trouver la position ou sera place le prochain index
// elle retourne la position
// le parametre 'p' est utilise lorsque l'on desire supprimer
// en effet, si p=true, on retourne 0 si l'element existe deja
// si p=false, on retourne la position ou se trouve l'element
int INDEX::cherchePosition(char * nom, int i, bool p)
{
	if (i > F.retourneMax()) return(0);
	if ((i-1) <= 0) return(i);

	// on regarde ou le nom se situe par rapport au premier element et au dernier
	if (compareAlphabet(nom,listeindex[i-1].cle) == 1) return (i);
	if (compareAlphabet(nom,listeindex[1].cle) == -1) return (1);

	// on effectue une recherche dichotomique
	int d,f,k,test;
	d=0;
	f=i;
	while (d+1 != f)
	{
		k=(d+f)/2;
		test=compareAlphabet(nom,listeindex[k].cle);
		if (test == 1) d=k;
		else if (test == 0)
		{
			if (p) return (0);
			else return (k);
		}
		else f=k;
	}
	return (f);
}


// cette fonction est utilisee pour la suppression
// elle est construite comme cherchePosition mais ne renvoit pas la meme chose
int INDEX::retournePosition(char * nom, int i)
{
	if (i > F.retourneMax()) return(-1);
	if ((i-1) <= 0) return(-1);
	if (compareAlphabet(nom,listeindex[i-1].cle) == 1) return (-1);
	if (compareAlphabet(nom,listeindex[1].cle) == -1) return (-1);

	int d,f,k,test;
	d=0;
	f=i;
	while (d+1 != f)
	{
		k=(d+f)/2;
		test=compareAlphabet(nom,listeindex[k].cle);
		if (test == 1) d=k;
		else if (test == 0) return (listeindex[k].chaine);
		else f=k;
	}
	return (-1);
}


// cette fonction est utilise pour comparer 2 chaines de caracteres
// elle retourne -1 si ch1 est placee avant (alphabetiquement) par rapport a ch2
// elle retourne 0 si ch1=ch2
// et 1 si ch1 est apres ch2
// il semblerait que la fonction strcmp() fasse la meme chose...
int INDEX::compareAlphabet(char * ch1, char * ch2)
{
	int lench1=strlen(ch1);
	int lench2=strlen(ch2);

	for (int i=0; (i < lench1) && (i < lench2); i++)
	{
		if (ch1[i] < ch2[i]) return(-1);
		if (ch1[i] > ch2[i]) return(1);
	}

	if (lench1 < lench2) return(-1);
	if (lench1 > lench2) return(1);
	return(0);
}


// cette fonction insere la cle passe en parametre a la position indiquee
// elle decale aussi tous les autres enregistrements
void INDEX::insereCle(char cle[], int chaine, int position)
{
	for (int j=nb_elt+1; j > position; j--) listeindex[j]=listeindex[j-1];
	strcpy(listeindex[position].cle,cle);
	listeindex[position].chaine=chaine;
}


// cette fonction decale tous les enresgitrements lorsqu'on fait une suppression
void INDEX::decaleIndex(int position)
{
	for (int j=position; j < nb_elt; j++) listeindex[j]=listeindex[j+1];
}


// cette fonction permet d'afficher les informations relatives a une cle
void INDEX::afficheFiche()
{
	char tempocle[32];
	cout << "\n\nRentrez le nom : ";
	cin >> tempocle;

	// on determine la position de la cle dans les index
	int position=retournePosition(tempocle,nb_elt);
	
	// if position == -1 la cle n'existe pas
	if (position == -1) cout << "\n=> Element introuvable";
	
	// on affiche le contenu de la fiche en question
	else F.affiche(position);

	cout << "\n\nAppuyez sur ENTREE pour continuer";
	getchar();
}

// fonction utilisee pour les tests
// affiche le contenu du tableau
void INDEX::affiche()
{
	for (int i=0; i < nb_elt; i++)
		cout << "\nCle = " << listeindex[i].cle << "\t|\tChaine =" << listeindex[i].chaine;
	cout << endl;
	getchar();
}

