/* Resolução do exercício 51 do caderno de exercícios de LP */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct nodo{
           char nome[40];
           int idade;
           struct nodo *next;
        } Tnodo;

/*     alínea a)      */
Tnodo *AddElem(Tnodo *first, Tnodo val){
   Tnodo *pnovo;
   if((pnovo=malloc(sizeof(Tnodo)))==NULL) {
		printf("Falha na alocação de memória!\n");
		return first;
   }
   *pnovo=val;	
   pnovo->next=first;		/* first pode estar a apontar para um nodo ou para NULL */
   return pnovo;			/* pnovo passa a ser o 1º da lista */
}

/*     alínea b)      */
void ListarTodos(Tnodo *first) {
   Tnodo *pn;
   printf("\n\n%-6s%s\n", "idade", "nome");
   for(pn=first; pn!=NULL; pn=pn->next)
      printf("%-6d%s", pn->idade, pn->nome);
}
   
/*     alínea c)      */
void Listar(Tnodo *first, char ch) {
   Tnodo *pn;
   printf("Funcinarios com nomes começados por %c\n", ch);
   printf("%-6s%s\n", "idade", "nome");
   for(pn=first; pn!=NULL; pn=pn->next)
	  if(pn->nome[0]==ch)
          printf("%-6d%s", pn->idade, pn->nome);
}
   
/*     alínea d)      */
Tnodo *RemElem(Tnodo *first, char *nome){
   Tnodo *q, *q_ant;
   q=first;
   while(q!=NULL && strcmp(q->nome, nome)!=0) { /* procura na lista o nodo a remover */
      q_ant=q;
      q=q->next;
   }
   if(q!=NULL)		/* nodo encontrado */
      if(q==first) {	 /* o nodo a remover é o 1º da lista */
         first=q->next; /* devolve o endereço do 2º nodo da lista, que passou a ser o 1º */
         free(q);
      } else { 
         q_ant->next=q->next;
         free(q);
      }
   return first;
} 

/*     alínea f)      */
Tnodo *RemTodos(Tnodo *first){
   if (first!=NULL) RemTodos(first->next);
   free(first);
   return NULL;
} 

/*     alínea g)      */
void gravarFicheiro(Tnodo *first) {
   FILE *pf;
   Tnodo *pn;
   if ((pf=fopen("xpto.fnc", "wb")) == NULL) {
      printf("Falha na abertura do ficheiro xpto.fnc!\n");
      return;
   }
   for(pn=first; pn!=NULL; pn=pn->next){
      fwrite(pn->nome, sizeof(char), 40, pf);
      fwrite(&pn->idade, sizeof(int), 1, pf);
	}
   fclose(pf);
}

/*     alínea h)      */
Tnodo *lerFicheiro(void) { /* carrega a lista com */
   FILE *pf;					   /* os elementos contidos no ficheiro xpto.fnc */
   Tnodo *first=NULL, no;
   if ((pf=fopen("xpto.fnc", "rb")) == NULL) {
      printf("Falha na abertura do ficheiro idades.dat!\n");
      return NULL;
   }
   while(fread(no.nome, sizeof(char), 40, pf)==40 && fread(&no.idade, sizeof(int), 1, pf)==1) 
       first=AddElem(first, no);
   fclose(pf);
   return first;
}

/*     alínea e)      */

char menu(void) {
   char op;
   printf("\n     N: Inserir novo funcionario\n");
   printf("     M: Mostrar listagem\n");
   printf("     I: Mostrar pela inicial\n");
   printf("     R: Remover funcionario\n");
   printf("     T: Remover Todos\n");
   printf("     L: Ler do ficheiro\n");
   printf("     G: Gravar no ficheiro\n");
   printf("     S: Sair\n");
   printf("\n opcao: ");
   scanf(" %c", &op); getchar();
   return op;
}

int main(){
   char opcao, inic;
   Tnodo novo, *lista=NULL;
   char nome[40];
   do {
      opcao=menu();
      switch (opcao) {
         case 'N':
         case 'n': printf(" nome: "); fgets(novo.nome, 40, stdin);
                   printf("idade: "); scanf("%d", &novo.idade);
                   lista=AddElem(lista, novo);
                   break;
         case 'M':
         case 'm': ListarTodos(lista);
                   break;
         case 'I':
         case 'i': printf("Inicial do nome: "); scanf(" %c", &inic);
                   Listar(lista, inic);
                   break;
         case 'R':
         case 'r': printf(" nome: "); fgets(nome, 40, stdin);
                   lista=RemElem(lista, nome);
                   break;
         case 'T':
         case 't': lista=RemTodos(lista);
                   break;
         case 'L':
         case 'l': lista=RemTodos(lista);
				   lista=lerFicheiro();
                   break;
         case 'G':
         case 'g': gravarFicheiro(lista);
                   break;
         case 's':
         case 'S': break;
         default : printf("Opcao invalida!\n");
      }
   }while (opcao!='s' && opcao!='S');
}

                /* resolvido por Paulo Gouveia */