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

#include "listas.h"
#include "leituras.h"

#define NOME_MAX 40

typedef struct
{
    char nome[NOME_MAX+1];
    double val;
} Var;


void erro(const char *mnsg)

{
    puts(mnsg);
    exit(EXIT_FAILURE);
}


Var *procura(Lista *vars, const char *nome)

{
    Var *var;
    
    for(var = Linicio(vars); var != 0; var = Lavanca(vars))
	if(strcmp(var->nome, nome) == 0)
	    return var;
    return 0;
}


void listar(Lista *vars, double ultimo)

{
    Var *var;
    
    printf("Variaveis:\n");
    for(var = Linicio(vars); var != 0; var = Lavanca(vars))
	printf("%s = %g\n", var->nome, var->val);
    printf("ultimo = %g\n", ultimo);
}


static void atribuicao(Lista *vars)

{
    Var *var;
    char nome[NOME_MAX];
    
    LEcadeia("Nome: ", nome, NOME_MAX);
    if((var = procura(vars, nome)) != 0)
	var->val = LEdouble("Valor: ");
    else
    {
	if((var = malloc(sizeof(*var))) == 0)
	    erro("Nao ha' memo'ria!");
	strcpy(var->nome, nome);
	var->val = LEdouble("Valor: ");
	if(LinsereInicio(vars, var) == 0)
	    erro("Erro inserindo!");
    }
}


static void adicao(Lista *vars, double *ultimo)

{
    Var *var1, *var2;
    char nome1[NOME_MAX], nome2[NOME_MAX];
    
    LEcadeia("Primeira: ", nome1, NOME_MAX);
    if((var1 = procura(vars, nome1)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome1);
	return;
    }
    LEcadeia("Segunda: ", nome2, NOME_MAX);
    if((var2 = procura(vars, nome2)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome2);
	return;
    }
    printf("%s + %s = %g + %g = %g\n", nome1, nome2, var1->val, var2->val,
	   *ultimo = var1->val + var2->val);
}


static void subtraccao(Lista *vars, double *ultimo)

{
    Var *var1, *var2;
    char nome1[NOME_MAX], nome2[NOME_MAX];
    
    LEcadeia("Primeira: ", nome1, NOME_MAX);
    if((var1 = procura(vars, nome1)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome1);
	return;
    }
    LEcadeia("Segunda: ", nome2, NOME_MAX);
    if((var2 = procura(vars, nome2)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome2);
	return;
    }
    printf("%s - %s = %g - %g = %g\n", nome1, nome2, var1->val, var2->val,
	   *ultimo = var1->val - var2->val);
}


static void multiplicacao(Lista *vars, double *ultimo)

{
    Var *var1, *var2;
    char nome1[NOME_MAX], nome2[NOME_MAX];
    
    LEcadeia("Primeira: ", nome1, NOME_MAX);
    if((var1 = procura(vars, nome1)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome1);
	return;
    }
    LEcadeia("Segunda: ", nome2, NOME_MAX);
    if((var2 = procura(vars, nome2)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome2);
	return;
    }
    printf("%s x %s = %g x %g = %g\n", nome1, nome2, var1->val, var2->val,
	   *ultimo = var1->val * var2->val);
}


static void divisao(Lista *vars, double *ultimo)

{
    Var *var1, *var2;
    char nome1[NOME_MAX], nome2[NOME_MAX];
    
    LEcadeia("Primeira: ", nome1, NOME_MAX);
    if((var1 = procura(vars, nome1)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome1);
	return;
    }
    LEcadeia("Segunda: ", nome2, NOME_MAX);
    if((var2 = procura(vars, nome2)) == 0)
    {
	fprintf(stderr, "\"%s\" nao existe!\n", nome2);
	return;
    }
    if(var2->val == 0)
    {
	fprintf(stderr, "Divisao por zero!\n");
	return;
    }
    printf("%s / %s = %g / %g = %g\n", nome1, nome2, var1->val, var2->val,
	   *ultimo = var1->val / var2->val);
}


static void guardar(Lista *vars, double val)

{
    Var *var;
    char nome[NOME_MAX];
    
    LEcadeia("Nome: ", nome, NOME_MAX);
    if((var = procura(vars, nome)) != 0)
	var->val = val;
    else
    {
	if((var = malloc(sizeof(*var))) == 0)
	    erro("Nao ha' memo'ria!");
	strcpy(var->nome, nome);
	var->val = val;
	if(LinsereInicio(vars, var) == 0)
	    erro("Erro inserindo!");
    }
}


int main(void)

{
    Lista *vars;
    int opcao;
    double ultimo = 0.0;
    
    if((vars = Lcria()) == 0)
	erro("Nao ha' memo'ria!");
    
    do
    {
        /* Perguntar opcao ao utilizador: */
        printf("\n"
	       "1 - Atribuir valor\n"
	       "2 - Soma\n"
               "3 - Subtraccao\n"
	       "4 - Multiplicacao\n"
               "5 - Divisao\n"
               "6 - Guarda ultimo\n"
               "7 - Mostrar variaveis\n"
	       "0 - Sair\n\n");
        switch(opcao = LEvalor("Opcao: [%d a %d] ", 0, 7))
        {
          case 1:
            atribuicao(vars);
            break;
          case 2:
            adicao(vars, &ultimo);
            break;
          case 3:
            subtraccao(vars, &ultimo);
            break;
          case 4:
	    multiplicacao(vars, &ultimo);
            break;
          case 5:
            divisao(vars, &ultimo);
            break;
          case 6:
            guardar(vars, ultimo);
            break;
          case 7:
            listar(vars, ultimo);
            break;
          case 0:
            break;
          default:
            /* Aqui nunca se pode chegar! */
            break;
        }
    }
    while(opcao != 0);

    Ldestroi(vars);
    
    return EXIT_SUCCESS;
}