/*
  .__       .           .     
  [__) _  _.|_  _ ._. _.|_  _ 
  |  \(/,(_.[ )(/,[  (_.[ )(/,...
     _     _                                          
    | |__ (_) __ _ _ __ __ _ _ __ ___  _ __ ___   ___ 
    | '_ \| |/ _` | '__/ _` | '_ ` _ \| '_ ` _ \ / _ \
    | |_) | | (_| | | | (_| | | | | | | | | | | |  __/
    |_.__/|_|\__, |_|  \__,_|_| |_| |_|_| |_| |_|\___|
             |___/                                    
	   
AUTEURS	: Aymeric & Ramazan
GROUPE	: RT (5)
DATE	: 21/03/2003
FICHIER	: bigramme.cpp

*/

#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include "bigramme.h"

// declaration de la fonction utilisee par qsort
static int compar(const void *,const void *);


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

Bigramme::Bigramme(char * nomfichier, int methode, int taille)
{
	int m1,m2,i=0,j=0,k;
	float p;
	Information aux;
	fonda=1;
	
	// si la methode 2 ou 3 ont ete demandees, on va creer un nouveau tableau
	if ((methode == 2) || (methode == 3))
	{
		taillefichier=taille;
		tableaumots=new Information [taillefichier];
	}
	
	// on lit le fichier data.model
	ifstream f(nomfichier);

	// on verifie que l'on peut le lire
	if (!f)
	{
		cout << "Impossible de lire le fichier " << nomfichier << endl;
	}
	else
	{	
		// on parcourt le fichier ligne par ligne jusqu'a End Of File
		while (!f.eof())
		{
			f >> m1 >> m2 >> p;
			
			// selon la methode employee on utilise differents algorithmes
			
			// methode de la liste chainee
			// on ajoute les informations grace a la fonction ajoute() de la classe Liste
			if (methode == 1)
			{
				listemots.ajoute(m1,m2,p);
				i++;
			}
						
			// methode des tableaux
			// on remplit le tableau
			else if ((methode == 2) || (methode == 3))
			{
				tableaumots[i].m1=m1;
				tableaumots[i].m2=m2;
				tableaumots[i].p=p;
				i++;
			}
			
			// la methode 4 correspond a celle des arbres
			else if (methode == 4)
			{
				aux.m1=m1;
				aux.m2=m2;
				aux.p=p;
				// on ajoute donc chaque information È l'arbre
				i=arbremots.ajoute_feuille(aux);
			}
		}
	
		f.close();
	}

	// on trie le tableau a l'aide de qsort
	if ((methode == 2) || (methode == 3)) qsort(tableaumots,taillefichier,sizeof(Information),&compar);

}


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

Bigramme::~Bigramme()
{
	// on detruit le tableau cree dynamiquement
	delete []tableaumots;
}


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

// cette fonction est appelee pour trouver un bigramme selon une methode
// elle retourne la probabilite trouvee, ou, si le bigramme n'est pas present, 0
// le parametre 'paspresent' sera utilise pour l'affichage
float Bigramme::recherche_Bigramme(int m1, int m2, int methode, bool paspresent)
{
	float p=0;
	Information aux;
	
	// methode des listes chainees
	// on utilise la fonction cherche_Bigramme() de la classe Liste
	if (methode == 1) p=listemots.cherche_Bigramme(m1,m2);
	
	// methode du tableau trie (recherche sequentielle)
	else if (methode == 2)
	{
		int i=0;
		
		// si m1 est inferieur a la plus basse des valeurs du tableau, alors on retourne 0
		if (m1 < tableaumots[i].m1) return(0);
		
		// sinon on parcourt tout le tableau a la recherche du couple (m1,m2)
		for (i=0; i < taillefichier; i++)
		{
			fonda++;
			if ((tableaumots[i].m1 == m1) && (tableaumots[i].m2 == m2))
			{
				p=tableaumots[i].p;
				break;
			}
		}
	}
	
	// methode du tableau trie (recherche dichotomique)
	else if (methode == 3)
	{
		int i=0,j=0,k;
		j=taillefichier;

		// utilisation de l'algorithme connu de la dichotomie
		while ( (i+1) < j )
		{
			fonda++;
			k = (int)((i+j)/2);
			
			if ( m1 > tableaumots[k].m1 ) i=k;
			else if ( (m1 == tableaumots[k].m1) && (m2 > tableaumots[k].m2) ) i=k;
			else if ( (m1 == tableaumots[k].m1) && (m2 < tableaumots[k].m2) ) j=k;
			else if ( (m1 == tableaumots[k].m1) && (m2 == tableaumots[k].m2) )
			{
				p=tableaumots[k].p;
				break;
			}
			else j=k;
		}
		
	}
	
	// methode des arbres
	else if (methode == 4)
	{
		aux.m1=m1;
		aux.m2=m2;
		// on utilise la fonction presentRecur() de la classe arbre pour rechercher la presence du bigramme
		p=arbremots.presentRecur(aux,fonda);
	}
	
	// si le bigramme a ete trouve (c-a-d p != 0) on l'affiche
	if (p != 0)
	{
		cout << "Le bigramme " << m1 << " et " << m2 << " est present, avec la probabilite p=" << p << endl;
	}
	// sinon, si on a choisi la recherche d'un seul bigramme, on affiche le message ci-dessous
	else if (!paspresent) cout << "\nLe bigramme " << m1 << " et " << m2 << " n'est pas present" << endl;
	
	// on retourne la probabilite
	return(p);
}

// cette fonction est utilisee lors du tri
// elle va permuter 2 informations entres elles
void Bigramme::permuteBigrammes(Information &m, Information &n)
{
	Information tmp;
	
	tmp.m1=m.m1;
	tmp.m2=m.m2;
	tmp.p=m.p;
	
	m.m1=n.m1;
	m.m2=n.m2;
	m.p=n.p;
	
	n.m1=tmp.m1;
	n.m2=tmp.m2;
	n.p=tmp.p;
}

// cette fonction affiche la memoire allouee
void Bigramme::memoire(int methode)
{
	if (methode == 1) cout << listemots.nb_element()*sizeof(Maillon) << " octets";
	else if ((methode == 2) || (methode == 3)) cout << taillefichier*sizeof(Information) << " octets";
	else cout << arbremots.nb_element()*sizeof(Information) << " octets";
}
	
// cette fonction est utilisee pour la comparaison de qsort
static int compar (const void *mail1,const void *mail2) {
		Information *m1;
		Information *m2;
		m1=(Information *)mail1;
		m2=(Information *)mail2;
		if (m1->m1 != m2->m1) return (m1->m1 - m2->m1);
		return (m1->m2 - m2->m2);
}
