/*
 * Cours Langage C - AIR1
 * C. Recanati 29/08/2019 14:47
 * TP4 exo3
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>		/* pour les erreurs sur les fichiers */
#include <string.h>		/* pour les chaines de caracteres */

#define MAXLINE	300			/* le nombre maximum de lignes d'un fichier */
#define MAX_SIZE_LINE 240  	/* la taille max d'une ligne */

/* types pour les listes (chainees) de mots */
struct s_mot {
	char * mot; 
	struct s_mot *suivant;
} ;	
typedef struct s_mot element; 
typedef  element*  liste_mots;

int isBlanc(char car); /* fonction boolenne: un caractere non imprimable ou blanc */

/* les fonctions sur les listes de mots */
void afficheListeMots(liste_mots list);	
element * newElem(char * mot);
liste_mots addBegin(liste_mots ls, element* nouv); /* ajout en tete de liste */
liste_mots addEnd(liste_mots ls, element* nouv); /* ajout en queue de liste */
liste_mots concatListe(liste_mots l1, liste_mots l2); /* prolonge l1 par l2 */
int taille(liste_mots ls); /* nb d'elements d'une liste de mots */

/* creation d'une liste de mots a partir d'un tableau de char ligne[] */
liste_mots creer(char ligne[], int n);

int compterOccur(char mot[], char ligne[]); /* nb d'occur. d'un mot dans une ligne */

/* variables globales au fichier */
char fichier_theme[40];		/* pour ouvrir le fichier des mots du theme */
FILE *fichierTheme;
char fichier_texte[40];		/* pour ouvrir le fichier du texte a categoriser */
FILE *fichierTexte;

int nb_line=0;	/* nb de lignes lues */
char ligne[MAX_SIZE_LINE]; /* ligne[] pour lire une ligne d'un fichier */

// Pour modifier le programme et utiliser
// un buffer pour lire le fichier texte d'un seul coup et pas ligne à ligne
// char buffer_texte[MAX_SIZE_LINE*MAXLINE];

// Pour modifier ce programme et faire un thematiseur general utilisant des thematiseurs
// spécialises afin de permettre de categoriser le texte en enumerant ses themes :
//liste_mots tab[MAXLINE];	/* tableau tab pour stocker des listes de mots thematiques */


int main(int argc, char* argv[]) {	
 	char *s; 	
	liste_mots  liste_theme = NULL, 
				liste = NULL;
	int nbMots=0, nbOccur=0, nbTotalOcc=0;

/* ouverture des fichiers */
	if (argc>1) {
		strcpy(fichier_theme, argv[1]);
		fichier_theme[strlen(argv[1])]= '\0';
		if (argc >= 3) {
			strcpy(fichier_texte, argv[2]);
			fichier_texte[strlen(argv[2])]= '\0';
		}
		else {
			printf("manque le nom du fichier a analyser\n");
			return EXIT_FAILURE;
		}
	}
	else {
		printf("Entrez un nom de fichier texte: ");
		scanf("%s", fichier_texte);
		printf("Entrez un nom de theme: ");
		scanf("%s", fichier_theme);
	}
 	fichierTheme = fopen(fichier_theme, "r");
 	if (fichierTheme == NULL) {
 		printf("impossible d'ouvrir %s ! erreur %d: %s\n", 
 					fichier_theme, errno, strerror(errno));
 		return errno;
 	}
 	fichierTexte = fopen(fichier_texte, "r");
 	if (fichierTexte == NULL) {
 		printf("impossible d'ouvrir %s ! erreur %d: %s\n", 
 					fichier_texte, errno, strerror(errno));
 		return errno;
 	}
 			
/* allocation de char *s pour lire une ligne, et initialisation de ligne[] */
	s = (char *) malloc(sizeof(char) * MAX_SIZE_LINE);
	ligne[MAX_SIZE_LINE-1]='\0';
	
 /* creer une liste de mots pour chaque ligne lue, et l'ajouter a liste_theme */
	while ((s = fgets(ligne, MAX_SIZE_LINE, fichierTheme)) != 0) {
		/* pour chaque ligne du fichier */
		ligne[strlen(ligne)-1] = '\0';
		liste = creer(ligne, strlen(ligne));
		liste_theme = concatListe(liste_theme, liste);
		//	variante:	tab[nb_line++] = liste;
	}
	afficheListeMots(liste_theme);

// variante: affichier toutes les listes de mots de differents themes
//	for(int i=0; i < nb_line; i++)
//		afficheListeMots(tab[i]);

/* lire maintenant le fichier texte ligne a ligne */
/* compter pour chaque ligne le nombre de mots de liste_mots présents */
/* ici parcourir liste_theme, et compter le nb de présence du mot dans la ligne */
	nbTotalOcc = 0; /* nb total de mots du theme figurant dans le texte */
	while ((s = fgets(ligne, MAX_SIZE_LINE, fichierTexte)) != 0) {
		/* pour chaque ligne du fichier texte */
		ligne[strlen(ligne)-1] = '\0';
		nbOccur = 0; /* nb d'occ. de mots du theme presents dans la ligne */
		for (element* p=liste_theme; p!=NULL; p=p->suivant) {
			nbOccur = nbOccur + compterOccur(p->mot, ligne);
		}
		nbTotalOcc = nbTotalOcc + nbOccur;		
	}	
	
/* calculer le pourcentage et l'imprimer */
		nbMots = taille(liste_theme);
		printf("nb de mots de la liste du theme = %d, nb d\'occurrences dans %s = %d\n", 
						nbMots, fichier_texte, nbTotalOcc);
	if (nbMots !=0)
		printf("le pourcentage est donc egal a %g pourcent\n", 
				(double) 100.0 *((double)nbTotalOcc/(double) nbMots));

/* fermer les fichiers ouverts */
	if (fclose(fichierTheme) == EOF)
		printf("erreur de fermeture du fichier %s\n", fichier_theme);
	if (fclose(fichierTexte) == EOF)
		printf("erreur de fermeture du fichier %s\n", fichier_texte);
	return EXIT_SUCCESS;
}

/* definition des fonctions utilisees dans le fichier et declarees en tête */

int isBlanc(char c) {
	if (((c==' ') || (c=='\t')) || (c=='\n'))
		return 1;
	if ((c=='\'') || (c=='\"'))
		return 1;	
	if ((int) c < 33)
		return 1;
	return 0;

}

/* creer retourne une liste de mots a partir des mots d'une ligne de n caracteres */
liste_mots creer(char ligne[], int n) {
		char *p,*q, *deb;
		char motlu[25];
		int i;
		liste_mots list = NULL;
		
		if (n ==0)
			return NULL;
		for (p= ligne; *p != '\0' ; p++) {	/* p parcourt la ligne */
			/* on recherche un mot */		
			for (q = p; (isBlanc(*q)==1); q++)
				; 		/* on "mange" les blancs (s'il y en a au debut) */		
			deb = q; /* le debut du mot eventuel suivant */
			i = 0; /* nombre de lettres du mot qu'on va mettre dans motlu */
//			while ( ((*q != ' ') && (*q != '\0')) && (*q != '\n')) {
			while ((isBlanc(*q)==0) && (*q !='\0')) {
				motlu[i++] =*q;
				q++; 	/* on avance q jusqu'a trouver un blanc (ou la fin) */
			}
			motlu[i] = '\0';
			if (i!= 0)
				list = addBegin(list, newElem(motlu)); /* ajout en tete */
			if (q-deb >0) { /* equivalent sans doute a n != 0 */
			/* alors on vient de franchir un mot d'au moins 1 caractere */
				p = q - 1; /* on avance p sur le dernier caractere du mot */			
			/* au prochain tour de boucle for, p sera incremente */
			/* et pointera finalement sur le meme char que q (celui après le mot) */
			}
		};
		return list;
}

element * newElem(char * motlu) {
	element * nouvElem = (element *) malloc(sizeof(element));
	char* motN = (char*) malloc (strlen(motlu)*sizeof(char));

	motN[strlen(motlu)] = '\0';
	nouvElem->mot = strcpy(motN, motlu); /* mot alloue statiquement */
    nouvElem->suivant = NULL;
    return nouvElem;
}

int taille(liste_mots ls){
	int nb = 0;
	for (element* p = ls; p != NULL; p=p->suivant)
		nb++;
	return nb;
}

void afficheListeMots(liste_mots list) {
	element * p  = list;
	
	if (p==NULL)
		return;	
	printf("(%s", p->mot);
	p = p->suivant;
	while ( p != NULL) {
      	printf(",%s", p->mot); // les suivants...
      	p = p-> suivant;
    }	
  	printf(")\n");
  	return;
}    

liste_mots addBegin(liste_mots ls, element* nouv) {
	nouv -> suivant = ls;
	return nouv;
}

liste_mots concatListe(liste_mots l1, liste_mots l2)
{
/* la fonction concatene 2 listes: elle permet de prolonger */
/* la liste l1 par une liste l2 et retourne l1 ainsi prolongee */

	liste_mots l = l1;
	if (l1 == NULL)
		return l2;
	while (l->suivant != NULL)
		l = l->suivant;
	l->suivant = l2;
	return l1;
}

liste_mots addEnd(liste_mots ls, element* nouv) {
	element* der;
	
	if (ls == NULL) 
			return nouv;
	if (ls->suivant == NULL) {
		ls->suivant = nouv;
		return ls;
	}
	for (element* p = ls ; p-> suivant != NULL; p = p->suivant)
		der = p;
	/* der pointe sur le dernier elem de ls */	
	der -> suivant = nouv;
	return ls;
}

/* compte les occurrences d'un mot dans une ligne */
int compterOccur(char mot[], char ligne[]) {
		char *p,*q, *deb;
		char motlu[25];
		int i;
		int nb = 0;
		
		if (mot==NULL)
			return 0;
		/* boucle similaire a celle dans creer(char ligne[], int n) */
		/* on aurait pu faire une fonction qui remplit motlu[] ? */
		for (p= ligne; *p != '\0' ; p++) {	/* p parcourt la ligne */
			/* on recherche un mot */		
			for (q = p; (isBlanc(*q) != 0); q++)
				; 		/* on "mange" les blancs (s'il y en a au debut) */		
			deb = q; /* le debut du mot eventuel suivant */
			i = 0; /* nombre de lettres du mot qu'on va mettre dans motlu */
//			while ( ((*q != ' ') && (*q != '\0')) && (*q != '\n')) {
			while ((isBlanc(*q)==0) && (*q !='\0')) {
				motlu[i++] =*q;
				q++; 	/* on avance q jusqu'a trouver un blanc (ou la fin) */
			}

			motlu[i] = '\0';
			if (i!= 0) 
				nb = nb + ( (strcmp(motlu, mot)==0) ? 1 : 0);
			if (q-deb >0) { /* equivalent sans doute a n != 0 */
			/* alors on vient de franchir un mot d'au moins 1 caractere */
				p = q - 1; /* on avance p sur le dernier caractere du mot */			
			/* au prochain tour de boucle for, p sera incremente */
			/* et pointera finalement sur le meme char que q (celui après le mot) */
			}
		}
		return nb;
}


