/* 
   Scritto di Fondamenti di Informatica
   Settembre 1999
   Ambiente e Territorio
*/

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

#define LEN 25

typedef enum {vero,falso} booleano;

typedef enum {okey,incoerente,incompleto} attributocodice;

struct cella {
	int molt;
	char cod1,cod2,cod3;
};

struct lista {
	char car;
	struct lista *next;
};


/* prototipi */
	void LeggiNomeFile(char *, char *);
	FILE *ApriFile(char *, char *);
	void AzzeraTavola(struct cella *);
	booleano Incoerente(struct cella[], char[]);
	struct lista *CreaElemento(void);
	void InTesta(char, struct lista **);
	void DistruggiLista(struct lista **);
	attributocodice Codifica(char *, char *, struct lista **);
	void StampaLista(struct lista *);
	int main(void);


void LeggiNomeFile(char *messaggio, char *nome)
{
	printf("%s",messaggio);
	gets(nome);
	return;
}


FILE *ApriFile(char *nome, char *modo)
{
	FILE *f;
	f=fopen(nome,modo);
	if(f==NULL) {
		fprintf(stderr,"Errore apertura file %s in modo %s. Esecuzione terminata.\n",nome,modo);
		exit(1);
	}
	return f;
}


void AzzeraTavola(struct cella *z)
{
	int i;
	
	for(i=0;i<26;i++)
		z[i].molt=0;
	return;
}


booleano Incoerente(struct cella x[], char nome[])
{
	FILE *f;
	char lett,a,b,c,newline;
	int i;
	
	AzzeraTavola(x);
	f=ApriFile(nome,"r");
	fscanf(f,"%c %c%c%c%c",&lett,&a,&b,&c,&newline);
	while(!feof(f)) {
		i=lett-'A';
		x[i].molt++;
		if(x[i].molt>1) {
			fclose(f);
			return vero; /* incoerente */
		}
		x[i].cod1=a;
		x[i].cod2=b;
		x[i].cod3=c;
		fscanf(f,"%c %c%c%c%c",&lett,&a,&b,&c,&newline);
	}
	fclose(f);
	return falso; /* coerente */
}


struct lista *CreaElemento(void)
{
	struct lista *nuovo;
	nuovo=malloc(sizeof(struct lista));
	if(nuovo==NULL) {
		fprintf(stderr,"Allocazione memoria fallita. Esecuzione terminata.\n");
		exit(2);
	}
	return nuovo;
}


void InTesta(char ch, struct lista **testa)
{
	struct lista *nuovo;
	
	nuovo=CreaElemento();
	nuovo->car=ch;
	nuovo->next=*testa;
	*testa=nuovo;
	return;
}


void DistruggiLista(struct lista **testa)
{
	struct lista *aux;
	while(*testa!=NULL) {
		aux=*testa;
		*testa=(*testa)->next;
		free(aux);
	}
	return;
}

attributocodice Codifica(char *cod, char *msg, struct lista **testa)
{
	struct cella tavola[26];
	FILE *f;
	int ch,i;
	
	*testa=NULL;
	
	if(Incoerente(tavola,cod)==vero)
		return incoerente;
	f=ApriFile(msg,"r");
	ch=fgetc(f);
	while(!feof(f)) {
		i=ch-'A';
		if(tavola[i].molt==0) {
			fclose(f);
			DistruggiLista(testa);
			return incompleto;
		}
		InTesta(tavola[i].cod1,testa);
		InTesta(tavola[i].cod2,testa);
		InTesta(tavola[i].cod3,testa);
		ch=fgetc(f);
	}
	fclose(f);
	return okey;
}


void StampaLista(struct lista *punt)
{
	for(;punt!=NULL;punt=punt->next)
		printf("%c",punt->car);
	printf("\n");
	return;
}


main(void)
{
	char filecod[LEN], filemsg[LEN];
	struct lista *primo;
		
	LeggiNomeFile("Inserisci nome file codice: ",filecod);
	LeggiNomeFile("Inserisci nome file messaggio: ",filemsg);
	switch(Codifica(filecod,filemsg,&primo)) {
		case incompleto: printf("Codice incompleto. Ciao.\n");
		                 break;
		case incoerente: printf("Codice incoerente. Ciao.\n");
		                 break;
		case okey: StampaLista(primo);
		           break;
	}
	return 0;
}