(*
 *  Programme tpnote
 *  Peio Loubière
 *  date 12-12-2011
 *  description programme corrigé
 *  version 1
 *)
program tpnote;
uses crt;
(*
 *  procedure afficheMenu
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description affiche le menu
 *  variable 
 *  retourne 
 *)
procedure afficheMenu();
begin
	 writeln('***************************************************');
	 writeln('***                    MENU                     ***');
	 writeln('*** 1 : Caracteres en commun                    ***');
	 writeln('*** 2 : Cryptographie                           ***');
	 writeln('*** 3 : Fonction f                              ***');
	 writeln('*** 4 : Bonus                                   ***');
	 writeln('*** 0 : Quitter                                 ***');
	 writeln('***************************************************');
	 writeln('Faites votre choix....');
end;

(*
 *  fonction menu
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description retourne le choix du menu ou redemmande si mauvaise saisie
 *  retourne le choix de l'utilisateur dans l'intervalle de valeur [0,4]
 *)
function menu() : char;
var
	 reponse : char;
begin
	 repeat
			afficheMenu();
			readln(reponse);
	 until reponse in ['0', '1', '2', '3', '4'] ; (* on affiche jusqu'à ce que le résultat soit compris dans un ensemble de valeurs  *)
	 menu := reponse;
end; {menu}

(*
 *  fonction appartient
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description vérifie sei la chaîne contient le caractère
 *  variable c : caractère probablement contenu
 *  variable ch : chaine contenant, éventuellement, le caractere
 *  retourne vrai si le caractère appartient à la chaine
 *)
function appartient(c	: char;  ch : string) : boolean;
var
	 pasTrouve	: boolean;
	 l, i		: integer; 
begin			
	 l := length(ch);
	 i := 1;
	 pasTrouve := TRUE;        (* on suppose que l'on n'a pas trouvé le caractère *)
	 while (i <= l) and (pasTrouve) do
	 begin
			pasTrouve := ch[i] <> c;      (* on a pas trouvé si les caractères sont différents *)
			i := i + 1;
	 end;
	 appartient := not pasTrouve;     (* le caractère appartient à la chaine si on l'a trouvé (donc non pasTrouve...) *)
end; { appartient }

(*
 *  fonction exo1
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description identifie les caractères en commun entre 2 chaines
 *  variable ch1 : 1er mot à comparer
 *  variable ch2 : 2nd mot à comparer
 *  retourne une chaine composée des caractères en commun entre ch1 et ch2, chaque caractère étant unique
 *)
function exo1(ch1, ch2 : string) : string;
var
	 retour, chTmp : string;
	 l1, l2, nbTmp, i : integer; 
begin
	 retour := ''; (* initialisation du résultat *)
	 
	 l1 := length(ch1); (* calcul des longueurs *)
	 l2 := length(ch2);
	 
	 if (l1 < l2) then (* comme on parcourt la 2nd chaine plusieurs fois, on va lui affecter celle de + petite taille *)
	 begin
			chTmp := ch1; (* permutation des chaines *)
			ch1 := ch2;
			ch2 := chTmp;

			nbTmp := l1; (* permutation des tailles (pour éviter le recalcul) *)
			l1 := l2;
			l2 := nbTmp;
	 end;

	 for i := 1 to l1 do (* pour chaque lettre du 1er mot... *)
	 begin
			if not appartient(ch1[i], retour) then  (* est-ce qu'elle n'est pas déjà en commun....*)
				 if appartient(ch1[i], ch2) then   (* est-ce qu'elle est dans le 2nd mot *)
						retour := retour + ch1[i];
	 end;
	 exo1 := retour;
end; { exo1 }


(*
 *  fonction exo2Term
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description crypte une phrase en décalant chaque lettre de n positions
 *  variable ch : phrase à crypter
 *  variable n  : entier, décallage de lettre
 *  variable i  : position de la lettre traitée dans la chaine
 *  variable res  : accumulateur de résultat, en fin de récursivité, contient la chaîne cryptée
 *  retourne la phrase cryptée
 *)
function exo2Term(ch : string; n : integer; i : integer; res : string) : string;
var
	 retour	: string;
begin			
	 if i > length(ch) then (* si l'on est en dehors de la chaîne, on retourne le résultat accumulé *)
			retour := res
	 else   (* sinon on décalle de n (modulo 128, taille de la table ascii) la lettre du mot et on passe au caractère suivant *)
			retour := exo2Term(ch, n, i+1, res + chr((ord(ch[i]) + n) mod 128));
	 exo2Term := retour;
end; { exo2Term }


(*
 *  fonction exo2
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description crypte une phrase en décalant chaque lettre de n positions
 *  variable ch : phrase à crypter
 *  variable n  : entier, décallage de lettre
 *  retourne la phrase cryptée
 *)
function exo2(ch : string; n	: integer) : string;
begin
   exo2 := exo2Term(ch, n, 1, '');
end; { exo2 }

(*
 *  fonction exo3
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description calcule f(n) = f(n-1) + 2f(n-2) + 3f(n-3)
 *  variable : n entier positif ou nul, variable de la fonction f
 *  retourne f(n)
 *)
function exo3(n	: longInt) : longInt;
var
	 res : longInt;
begin
	 if (n < 3) then
			res := n
	 else
			res := exo3(n-1) + 2*exo3(n-2) + 3*exo3(n-3);
	 exo3 := res;
end; {exo3}


(*
 *  fonction exo4
 *  auteur : Peio Loubière
 *  date 12-12-2011
 *  description trouve les mots les plus long et plus court dans une phrase donnée
 *  variable ph : phrase à analyser
 *  variable court mot le plus court, vide
 *  variable long mot le plus long, vide
 *  retourne court et long contenant une valeur
 *)
procedure exo4(ch	: string; var court :  string; var long	: string);
var
	 l, lmot, i	: integer;
	 mot	: string;
begin
	(* initialisation *)
	 l := length(ch);
	 mot := '';

	 for i := 1 to l do (* parcours de la phrase *)
	 begin
			if ch[i] <> ' ' then (* on n'a pas fini de parcourir un mot*)
			begin
				 mot := mot + ch[i];
			end
			else (* l'espace sépare 2 mots, on compare le mot restitué avec les résultats  *)
			begin
				 lmot := length(mot);
				 if lmot > length(long) then
						long := mot;
				 if (lmot < length(court)) or (court = '') then
						court := mot;
				 mot := ''; (* on ré-initialise pour un nouveau mot *)
			end;
	 end;
	 (* test supplémentaire pour le dernier mot *)
	 lmot := length(mot);
	 if lmot > length(long) then
			long := mot;
	 if (lmot < length(court)) or (court = '') then
			court := mot;				 
end;

var
	 rep																	: char;
	 phrase, ch1, ch2, resCh, long, court	: string;
	 nb																		: integer;
	 nblong, resLong											: longInt;
																				
begin
	 
	 rep := menu(); (* on récupere la réponse et on la teste *)
	 repeat
			case rep of
				'1'	: begin
					 writeln('Saisissez un mot....');
					 readln(ch1);
					 writeln('Un autre....');
					 readln(ch2);
					 resCh := exo1(ch1, ch2);
					 if length(resCh) = 0 then
							writeln('il n''y a aucun caractère en commun')
					 else
							writeln('Les caractères en commun sont : ' + resCh);
					 rep := menu(); (* on relance le menu *)
				end;
				'2'	: begin
					 writeln('Saisissez une phrase à crypter....');
					 readln(phrase);
					 writeln('Saisissez le décallage ....');
					 readln(nb); 
					 resCh := exo2(phrase, nb);
					 writeln('Cyptage... : ');
					 writeln(resCh);
					 rep := menu(); (* on relance le menu *)
				end;
				'3'	: begin
					 repeat  (* test pour précondition n >= 0*)
							writeln('Saisissez un nombre positif ou nul....');
							readln(nbLong);
					 until nbLong >= 0;
					 resLong := exo3(nbLong);
					 writeln('f(',nbLong,') = ',resLong);
					 rep := menu(); (* on relance le menu *)
				end;
				'4'	: begin
					 court := '';
					 long := '';
					 writeln('Saisissez une phrase....');
					 readln(phrase);
					 exo4(phrase, court, long);
					 writeln('Mot le plus court : ',court,', le plus long : ',long);					 
					 rep := menu(); (* on relance le menu *)
				end;
			end;
	 until (rep = '0'); (* arret du programme *)
	 clrScr();
	 writeln('A bientôt !!');		
end.
