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

typedef struct{
    char nombre[30];
    int precio;
}productos;      //Estructura que define producto


typedef struct lista_prod{
    productos p;
    struct lista_prod *sig;
}prod; //Estructura utilizada para lista de productos.

typedef struct lista_tienda{
    char nombre[30];
    prod *d;
    struct lista_tienda *sig;
}tienda; //Estructura utilizada para lista de tiendas.

void AgregarTienda(tienda **lista); //Agrega Tienda
void AgregarProductos(tienda **lista);// Agrega productos a una tienda
void MostrarTiendas(tienda *lista);   //Muestra tienda y productos
void MostrarProductos(tienda *lista);//Funcion auxiliar llamada en la funcion MostrarTiendas
void GuardarDatos(tienda *lista); //Guarda datos en binario
void CargarDatos(tienda **lista); //Lee desde datos guardados
void BorrarDatos(tienda **lista); //Usada para liberar la memoria utilizada

int main()
{
    char opcion;
    tienda *lista=NULL;

    while(1)
    {
        system("cls");
        printf("****************************\n"
               "Tiendas y Productos\n"
               "****************************\n");
        printf("1.- Agregar Tienda\n"
               "2.- Agregar Producto\n"
               "3.- Ver Catalogo\n"
               "4.- Guardar Catalogo\n"
               "5.- Cargar Catalogo\n"
               "6.- Salir\n");
        while(opcion=getch(), opcion<'1'||opcion>'6');//Menú

        switch(opcion)
        {
            case '1':
                AgregarTienda(&lista);break;
            case '2':
                AgregarProductos(&lista);break;
            case '3':
                MostrarTiendas(lista);break;
            case '4':
                GuardarDatos(lista);break;
            case '5':
                CargarDatos(&lista);break;
            case '6':
                system("pause");return 0;
        }
        system("pause");
    }
}

void AgregarTienda(tienda **lista)
{
    tienda *nodo=NULL, *rec=NULL; //Punteros a la estructura tiendas

    nodo=(tienda*)malloc(sizeof(tienda)); //Se reserva memoria para crear nodo.
    if(!nodo) //Habrá memoria disponible?
    {
        printf("No hay memoria disponible.\n");
        return;
    }

    printf("Ingrese nombre de la tienda: "); //Se llenan los datos necesarios.
    gets(nodo->nombre);

    nodo->d=NULL;  //La tienda se ha creado recien por lo tanto no tiene productos.
    nodo->sig=NULL;//Nodo siguiente aun no existe por lo tanto apunta a NULL.
    if(!*lista) //Si no hay lista se crea.
        *lista=nodo;
    else{
        rec=*lista; //Si hay, se agrega nodo al final de ésta.
        while(rec->sig)
            rec=rec->sig;
        rec->sig=nodo;
    }
}

void AgregarProductos(tienda **lista)
{
    char n_tienda[30];
    tienda *rec_t=NULL;
    prod *rec_p=NULL, *nuevo_p=NULL;

    if(!*lista) //Hay lista?
    {
        printf("No hay tiendas.\n");
        return;
    }

    printf("Ingrese nombre de la tienda a la cual desea agregar producto:\n");
    gets(n_tienda); //Se ingresa nombre de la tienda a la cual agregar el producto.
    rec_t=*lista;
    while(rec_t) //Se busca la direccion de dicha tienda.
    {
        if(stricmp(n_tienda,rec_t->nombre)==0)
            break;
        rec_t=rec_t->sig;
    }
    if(!rec_t) //Existe la tienda buscada?
    {
        printf("No se encontr%c tienda especificada.\n", 162);
        return;
    }

    nuevo_p=(prod*)malloc(sizeof(prod)); //Se reserva memoria para los productos de la tienda.
    if(!nuevo_p) //Habrá memoria disponible?
    {
        printf("No hay memoria suficiente.\n");
        return;
    }
    printf("Ingrese nombre del producto a agregar: ");
    gets(nuevo_p->p.nombre); //Se ingresan los datos del producto.
    printf("Ingrese el precio del producto: $");
    scanf("%d", &nuevo_p->p.precio);
    fflush(stdin);  //Se limpia posible basura que quede en buffer de entrada.
    nuevo_p->sig=NULL;

    if(!rec_t->d)  //Si no habia una lista de productos se crea.
        rec_t->d=nuevo_p;
    else{
        rec_p=rec_t->d; //Si había, se agrega nodo al final.
        while(rec_p->sig)
            rec_p=rec_p->sig;
        rec_p->sig=nuevo_p;
    }
}
void MostrarTiendas(tienda *lista)
{
    tienda *rec=NULL; //Variable utilizada para recorrer la lista.
    rec=lista; //Se le da la direccion del nodo inicial de la lista.

    while(rec) //Mientras hayan datos...
    {
        printf("Tienda: %s\n\n", rec->nombre); //Se muestra nombre de tienda.
        MostrarProductos(rec); //Se llama a la funcion mostrar productos
        rec=rec->sig; //SE recorre la lista.
    }
}
void MostrarProductos(tienda *lista)
{
    prod *rec=NULL;

    rec=lista->d;  //Se le da a rec la direccion del nodo inicial de productos de la tienda.
    while(rec) //MIentras hayan datos se muestran.
    {
        printf("Producto: %s\n", rec->p.nombre);
        printf("Precio: $%d\n\n", rec->p.precio);
        rec=rec->sig;
    }
}
void GuardarDatos(tienda *lista)
{
    FILE *archivo; //Puntero a FILE.
    tienda *rec_t=NULL; //Punteros para recorrer lista de tiendas y productos.
    prod *rec_p=NULL;
    productos delimitador; //Variable auxiliar que ayudará posteriormente a la carga de archivos
    char fint[30];   //Analogo al delimitador.
    archivo=fopen("Catalogo.dat","wb"); //Se abre archivo para escritura en binario.
    if(!archivo) //Se pudo abrir archivo?
    {
        printf("No se pudo abrir archivo.\n");
        return;
    }
    rec_t=lista; //El rec_t apunta al nodo inicial de la lista de tiendas.
    strcpy(delimitador.nombre,"$$$.del"); //Clave para poder cargar los archivos despues.
    strcpy(fint,"fintiend.$$$"); //Analogo a lo anterior
    delimitador.precio=10101; //Analogo
    while(rec_t) //Mientras hayan datos
    {
        fwrite(&rec_t->nombre,sizeof(char),30,archivo); //Se escribem en archivo
        rec_p=rec_t->d;
        while(rec_p) //En este ciclo se escriben los productos de la tienda.
        {
            fwrite(&rec_p->p,sizeof(productos),1,archivo);
            rec_p=rec_p->sig;
        }
        fwrite(&delimitador,sizeof(productos),1,archivo); //Al final de los productos se escribe el delimitador.
        rec_t=rec_t->sig; //Se avanza al siguiente nodo
    }
    fwrite(fint,sizeof(char),30,archivo); //Palabra clave que indica final del fichero-

    fclose(archivo);
    printf("Datos guardados!\n");

}
void CargarDatos(tienda **lista)
{
    FILE *archivo; //Analogo al caso de guardar lista.
    tienda *rec_t=NULL, *nodo_t=NULL;
    prod *rec_p=NULL, *nodo_p=NULL;
    productos p;
    char buffer[30];

    archivo=fopen("Catalogo.dat","rb"); //Se abre archivo para lectura en binario.

    if(!archivo)
    {
        printf("No se pudo abrir archivo.\n");
        return;
    }

    if(*lista) //Si había lista se borra.
        BorrarDatos(lista);

    while(1)
    {
        fread(&buffer,sizeof(char),30,archivo); //Se lee el nombre de la tienda.
        if(strcmp(buffer,"fintiend.$$$")==0) //SI se lee palabra clave, significa que no hay mas datos por leer.
            break; //Se rompe ciclo
        nodo_t=(tienda*)malloc(sizeof(tienda)); //Se reserva memoria para tienda
        nodo_t->sig=NULL; //Nodo siguiente al creado apunta a NULL
        nodo_t->d=NULL;  //Inicialmente no se han leido productos, por tanto aputnta a NULL
        strcpy(nodo_t->nombre,buffer); //Se le da el nombre leido desde archivo a la tienda.
        if(!*lista) //Se crea primer elemento a la lista en la primera iteracion.
            *lista=nodo_t;
        else{
            rec_t=*lista; //Luego se agregan nodos al final de la lista.
            while(rec_t->sig)
                rec_t=rec_t->sig;
            rec_t->sig=nodo_t;

        }
        rec_t=nodo_t;
        while(1)
        {
            fread(&p, sizeof(productos),1,archivo); //En este ciclo se leen los productos.
            if(strcmp(p.nombre,"$$$.del")==0&&p.precio==10101) //Si se encuentra delimitador se rompe ciclo.
                break;
            nodo_p=(prod*)malloc(sizeof(prod)); //Se reserva memoria para los productos.
            nodo_p->p=p;
            nodo_p->sig=NULL;
            if(!rec_t->d) //Se llena la lista de productos.
                rec_t->d=nodo_p;
            else{
                rec_p=rec_t->d;
                while(rec_p->sig)
                    rec_p=rec_p->sig;
                rec_p->sig=nodo_p;
            }
        }
    }
    fclose(archivo); //Se cierra archivo.
    printf("Carga Exitosa!\n");
}

void BorrarDatos(tienda **lista)
{
    tienda *aux1=NULL;
    prod *aux2=NULL,*rec=NULL;
    do{
        aux1=(*lista)->sig; //Se recorren ambas listas y se libera la memoria utilizada.
        rec=(*lista)->d;
        if(rec){
            do{
                aux2=rec->sig;
                free(rec);
                rec=aux2;

            }while(aux2);
        }
        free(*lista);
        (*lista)=aux1;
    }while(aux1);
    *lista=NULL;
    return;
}
