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

/* Macros relacionadas com o numero maximo de caracteres num nome e com o
   tamanho das matrizes de char necessarias para os guardar: */
#define NOME_MAX 40
#define NOMEMAT_MAX (NOME_MAX + 1)

/* Macro que define o numero maximo de utentes: */
#define UTENTES_MAX 50

/* Definicao da estrutura que guarda informacao acerca de um utente: */
typedef struct Utente
{
    char nome[NOMEMAT_MAX];
    int categoria;
    int codigo;
} Utente;


/* Le utentes dum ficheiro. Devolve o numero de utentes lidos:  */
int leUtentes(Utente utentes[], FILE *entrada)

{
    int i;

    for(i = 0; i < UTENTES_MAX; i++)
    {
        if(fgets(utentes[i].nome, NOMEMAT_MAX, entrada) == NULL ||
           fscanf(entrada, "%d%d ", &utentes[i].categoria,
		  &utentes[i].codigo) != 2)
            break;
        if(utentes[i].nome[strlen(utentes[i].nome)-1] == '\n')
            utentes[i].nome[strlen(utentes[i].nome)-1] = '\0';
    }
    return i;
}


/* Guarda lista de utentes num ficheiro (a informacao que existia no
   ficheiro e' descartada): */
void guardaUtentes(Utente *ordena[], FILE *saida, int n)

{
    int i;
    
    /* Escreve utentes: */
    for(i = 0; i < n; i++)
    {
	fprintf(saida, "%s\n", ordena[i]->nome);
	fprintf(saida, "%d\n", ordena[i]->categoria);
	fprintf(saida, "%d\n", ordena[i]->codigo);
    }

    /* Verifica se houve erros de escrita: */
    if(ferror(saida))
    {
        fprintf(stderr, "Erro: escrevendo no ficheiro!\n");
	exit(EXIT_FAILURE);
    }
}


/* Note-se a utilizacao da ordenacao por permutacao (em ingles "bubble
   sort") */
void ordenaUtentes(Utente *ponteiros[], int usaNome, int n)

{
    Utente *temp;
    int topo, limite, i;

    topo = n - 1;
    /* Por uma questao de eficiencia repete-se o codigo de ordenacao: */
    if(usaNome)
	do
	{
	    limite = topo;
	    topo = 0;
	    for(i = 0; i < limite; i++)
		if(strcmp(ponteiros[i]->nome, ponteiros[i+1]->nome) > 0)
		{
		    temp = ponteiros[i];
		    ponteiros[i] = ponteiros[i+1];
		    ponteiros[i+1] = temp;
		    topo = i;
		}
	}
	while(topo != 0);
    else
	do
	{
	    limite = topo;
	    topo = 0;
	    for(i = 0; i < limite; i++)
		if(ponteiros[i]->codigo > ponteiros[i+1]->codigo)
		{
		    temp = ponteiros[i];
		    ponteiros[i] = ponteiros[i+1];
		    ponteiros[i+1] = temp;
		    topo = i;
		}
	}
	while(topo != 0);
}

/* Programa principal: */
int main(int argc, char *argv[])

{
    Utente utentes[UTENTES_MAX];
    Utente *ponteiros[UTENTES_MAX];
    int usaNome, i, n;
    FILE *entrada, *saida;
    
    if(argc > 4)
    {
	fprintf(stderr, "Numero de argumentos invalido.\n"
		"%s [entrada [saida [nome/codigo]]]\n", argv[0]);
	return EXIT_FAILURE;
    }

    /* Valores por omissao: */
    entrada = stdin;
    saida = stdout;
    usaNome = 1;
    
    /* Le opcoes e abre ficheiros: */
    switch(argc)
    {
      case 4:
	if(strcmp(argv[3], "nome") == 0)
	    usaNome = 1;
	else if(strcmp(argv[3], "codigo") == 0)
	    usaNome = 0;
	else
	{
	    fprintf(stderr, "Argumento 3 invalido!\n");
	    return EXIT_FAILURE;
	}
      case 3:
	if((saida = fopen(argv[2], "w")) == 0)
	{
	    fprintf(stderr, "Erro criando o ficheiro \"%s\".\n", argv[2]);
	    return EXIT_FAILURE;
	}
      case 2:
	if((entrada = fopen(argv[1], "r")) == 0)
	{
	    fprintf(stderr, "Erro abrindo o ficheiro \"%s\".\n", argv[1]);
	    return EXIT_FAILURE;
	}
      default:
	break;
    }
    
    /* Ler ficheiro: */
    n = leUtentes(utentes, entrada);
    
    /* Ordena utentes: */
    for(i = 0; i < n; i++)
	ponteiros[i] = &utentes[i];
    ordenaUtentes(ponteiros, usaNome, n);

    /* Guarda utentes: */
    guardaUtentes(ponteiros, saida, n);
    
    /* Fecha ficheiros: */
    switch(argc)
    {
      case 4:
      case 3:
	fclose(saida);
      case 2:
	fclose(entrada);
      default:
	break;
    }
    return EXIT_SUCCESS;
}