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

typedef struct lista{

    char nombre[20];
    char direccion[20];
    int cuenta;
    struct lista *sig;    //Puntero a nodo siguiente de la lista.
    struct lista *ant;    //Puntero a nodo anterior.
}persona;

persona *CrearLista(void);// Crea una lista de personas
void InsertarLista(persona **lista); // Inserta persona en una lista creada, si no hay lista ls crea
void MostrarLista(persona *lista); //Muestra la lista en pantalla.
int GuardarLista(char *n_archivo, persona *lista); //Guarda una lista en archivo
int CargarLista(persona **lista, char *n_archivo); //Carga una lista desde archivo
void BuscarPersona(persona *lista, char *nombre);//Busca una persona en una lista
int BuscarCoincidencia(char *a, char *b);
int BorrarPersona(persona **lista, char *nombre); //Borra a una persona de la lista.
void MostrarListaInvertida(persona *lista); //Muestra la lista de forma invertida en pantalla.
int EditarPersona(persona *lista, char *nombre);

int main()
{
    char opcion, nombre_archivo[20], nombre[20];
    persona p, *lista=NULL;
    while(1)
    {
            system("cls");
            printf("1.- Crear Lista\n"
                   "2.- Agregar a Lista\n"
                   "3.- Mostrar lista\n"
                   "4.- Guardar lista\n"
                   "5.- Cargar lista\n"
                   "6.- Buscar Persona\n"
                   "7.- Borrar Persona\n"
                   "8.- Editar Persona\n"
                   "9.- Salir"
                   );
            printf("\n\n");
        while(opcion=getch(), opcion<'1' || opcion>'9');
        fflush(stdin);

        switch(opcion)
        {
            case '1':
                printf("---------------------\n"
                       " Crear Lista\n"
                       "---------------------\n");
                lista=CrearLista();break;
            case '2':
                printf("---------------------\n"
                       " Agregar Persona\n"
                       "---------------------\n");
                InsertarLista(&lista);break;
            case '3':
                printf("---------------------\n"
                       " Lista de Personas\n"
                       "---------------------\n");
                MostrarLista(lista);
                system("pause");break;
            case '4':
            {
                printf("---------------------\n"
                       " Guardar Lista\n"
                       "---------------------\n");
                printf("Ingrese nombre del archivo:\n");
                gets(nombre_archivo);
                GuardarLista(nombre_archivo, lista);
                break;
            }
            case '5':
            {
                printf("---------------------\n"
                       " Cargar Lista\n"
                       "---------------------\n");
                printf("Ingrese nombre del archivo:\n");
                gets(nombre_archivo);
                CargarLista(&lista, nombre_archivo);
                system("pause");
                break;
            }
            case'6':
            {
                printf("---------------------\n"
                       " Buscar Persona\n"
                       "---------------------\n");
                printf("Ingrese nombre de persona a buscar:\n");
                gets(nombre);
                BuscarPersona(lista, nombre);
            }break;
            case '7':
            {
                printf("---------------------\n"
                       " Eliminar Persona\n"
                       "---------------------\n");
                printf("Ingrese nombre de persona que desee eliminar de la lista:\n");
                gets(nombre);
                BorrarPersona(&lista, nombre);
                system("pause");
            }break;
            case '8':
            {
                printf("---------------------\n"
                       " Editar Persona\n"
                       "---------------------\n");
                printf("Ingrese nombre de persona que desee editar de la lista:\n");
                gets(nombre);
                EditarPersona(lista, nombre);
                system("pause");
            }break;
            case '9':
            {
                system("pause");
                return 0;
            }
        }


    }
}

persona *CrearLista(void)
{
    persona *r=NULL;       //Puntero a estructura
    r=(persona*)malloc(sizeof(persona)); //Reserva memoria
    printf("Ingrese nombre:\n");
    gets(r->nombre);
    printf("Ingrese direcci%cn\n", 162);
    gets(r->direccion);
    printf("Ingrese saldo en la cuenta:\n");
    scanf("%d", &r->cuenta);
    fflush(stdin);
    r->sig=NULL;   //Elemento siguiente y anterior deben apuntar a NULL
    r->ant=NULL;
    return r;    //Se retorna un puntero que apunta al primer elemento de la lista.
}

void InsertarLista(persona **lista) //Paso por referencia a la lista.
{
    persona *nodo, *rec;     //punteros a la estrucura
    nodo=(persona*)malloc(sizeof(persona)); //Se crea nodo para la lista

    nodo->sig=NULL;       //Elemento siguiente al nuevo nodo apunta a NULL
    nodo->ant=NULL;       //Se inicializa el elemento anterior a la lista.
    printf("Ingrese nombre:\n");
    gets(nodo->nombre);
    printf("Ingrese direcci%cn\n", 162);
    gets(nodo->direccion);
    printf("Ingrese saldo en la cuenta:\n");
    scanf("%d", &nodo->cuenta);
    fflush(stdin);
    if(*lista==NULL) //Si la lista estaba vacia se crea.
        *lista=nodo;
    else{
        rec=*lista;   //Se recorre la lista hasta que el siguiente elemento apunte a NULL
        while(rec->sig!=NULL)
            rec=rec->sig;
        nodo->ant=rec; //El valor anterior del nodo nuevo es el valor final de la lista.
        rec->sig=nodo; //El valor siguiente a la lista es el nodo.

    }
}

void MostrarLista(persona *lista)
{
    if(lista) //Si hay lista...
    {
        printf("Nombre: ");
        puts(lista->nombre);
        printf("Direcci%cn: ",162);
        puts(lista->direccion);
        printf("Saldo: %d\n\n", lista->cuenta);
        MostrarLista(lista->sig); //Se muestra de forma recursiva
    }
}

void MostrarListaInvertida(persona *lista)
{
    persona *rec=NULL;

    rec=lista;   //Se hace apuntar rec a lista.
    while(rec->sig!=NULL) //Se recorre hasta llegar al final de la lista.
        rec=rec->sig;
    while(rec!=NULL)  //mientras rec no apunte a NULL
    {
        puts(rec->nombre);
        puts(rec->direccion);
        printf("%d\n", rec->cuenta);
        rec=rec->ant;  //Se recorre la lista en forma invertida
    }
}

int GuardarLista(char *n_archivo,persona *lista)
{
    int i=0;
    persona *rec=NULL;
    strcat(n_archivo,".txt");
    FILE *archivo=fopen(n_archivo, "wt"); //puntero a file.

    rec=lista;
    if(archivo) //Si no hubo problemas
    {
        fprintf(archivo, "\tDatos Guardados:\n\n"); //Se escribe en archivo.
        while(rec)
        {
            fprintf(archivo, "Persona %d:\n\n", i+1);
            fprintf(archivo, "Nombre:\n");
            fputs(rec->nombre,archivo);
            fprintf(archivo,"\n");
            fprintf(archivo, "Direccion:\n");
            fputs(rec->direccion,archivo);
            fprintf(archivo,"\n");
            fprintf(archivo, "Saldo de cuenta:\n");
            fprintf(archivo, "%d\n", rec->cuenta);
            rec=rec->sig;
            i++;
        }
        printf("Datos Guardados!\n");
		fclose(archivo); // Se cierra archivo
    }else{
		printf("No se pudo abrir archivo.\n");
        return 1;
	}
    return 0;  //Si hubo exito retorna 0
}

int CargarLista(persona **lista, char *n_archivo)  //Se lee de la misma forma en que fue escrito
{
    char buffer[80];   //Para saltar datos que no pertenecen a la lista
    FILE *archivo=NULL;
    persona *r=NULL, *aux;
    strcat(n_archivo,".txt");
    archivo=fopen(n_archivo, "rt");

    if(archivo==NULL)
    {
        printf("No se pudo abrir archivo.\n");
        return 1;
    }
    (*lista)=(persona*)malloc(sizeof(persona));
    r=*lista;
    r->ant=NULL;

    fgets(buffer,80,archivo); //Descartar 2 primeras lineas
    fgets(buffer,80,archivo);
    while(1)
    {
        fgets(buffer,80,archivo);  //Descarta las líneas que no contienen datos.
        fgets(buffer,80,archivo);
        fgets(buffer,80,archivo);
        fgets(r->nombre, 20, archivo);
        strtok(r->nombre, "\n");      //Destruye la cadena, eliminando el salto de linea agregado por fgets.
        fgets(buffer,80,archivo);
        fgets(r->direccion, 20, archivo);
        strtok(r->direccion, "\n");
        fgets(buffer,80,archivo);
        fscanf(archivo,"%d\n",&r->cuenta);
        r->sig=NULL;
        if(feof(archivo))
            break;
        r->sig=(persona*)malloc(sizeof(persona));
        aux=r;
        r=r->sig;
        r->ant=aux;
    }

    fclose(archivo);
    printf("La carga ha sido exitosa!\n");
    return 0;

}

void BuscarPersona(persona *lista, char *nombre)
{
    persona *rec=NULL;
    int verif=0;

    if(lista==NULL) //Habra lista?
    {
        printf("No hay una lista cargada.\n");
        system("pause");
        return;
    }

    rec=lista;

    while(rec!=NULL)//Se recorre la lista...
    {   //Se buscan las coincidencias
        if(BuscarCoincidencia(nombre,rec->nombre)==0 || strcmp(rec->nombre,nombre)==0)
        {
            verif++;
            printf("Coincidencia n%d:\n", verif);
            puts(rec->nombre);
            puts(rec->direccion);
            printf("%d\n", rec->cuenta);
        }
        rec=rec->sig;
    }
    if(verif==0)
    {
        printf("No se encontraron coincidencias.\n");
    }
    system("pause");
    return;
}

int BorrarPersona(persona **lista, char *nombre)
{
    persona *rec=NULL, *ant; //ant es variable auxiliar

    if(*lista==NULL)
    {
        printf("No hay lista cargada.\n");
        return 1;
    }

    rec=*lista; //Se utiliza rec para recorrer la lista
    while(rec!=NULL)
    {
        ant=rec->ant; //ant apunta al dato que se encuentra en el nodo anterior al dato que apunta rec.
        if(strcmp(rec->nombre,nombre)==0) //Si se encuentra a la persona...
        {   if(rec->ant==NULL) //si se encuentra al inicio de la lista
            {
                if(rec->sig!=NULL) //Si hay elemento siguiente...
                {
                    (*lista)=(*lista)->sig;
                    (*lista)->ant=NULL;
                }
                else
                    *lista=NULL; //Sino la lista apunta a NULL.
            }
            else
            {
               if(rec->sig!=NULL) //Si hay elemento siguiente
                  ant->sig=rec->sig; //El elemento anterior al rec, apunta al elemento siguiente del recorrido
               else
                  ant->sig=NULL; //Si estamos al final de la lista el anterior apunta a NULL
            }
            free(rec); //Se libera la memoria del puntero rec
            printf("Se ha eliminado la persona indicada.\n");
            return 0;
        }
        rec=rec->sig;
    }
    printf("No se encontr%c persona a eliminar.\n", 162);
    return 1;
}

int BuscarCoincidencia(char *a, char *b)
{
    int i;

    a[0]=toupper(a[0]); //Pone mayuscula al inicio de la palabra a buscar
    for(i=1;i<strlen(a);i++) //Hace minusculas todas las otras letras
        a[i]=tolower(a[i]);
    if(strstr(b,a)!=NULL)  //Busca alguna coincidencia del string a en b
        return 0; //Si hubo exito se retorn 0.
    return 1;
}

int EditarPersona(persona *lista, char *nombre)
{
    char c;
    if(lista==NULL) //Habra lista?
    {
        printf("No hay personas ingresadas.\n");
        return 1;
    }

    while(lista!=NULL)  //Mientras existan datos a leer...
    {
        if(strcmp(lista->nombre, nombre)==0) //Si se encontro persona a editar...
        {
            printf("Editar Nombre?\n(s/n)\n\n");
            while(c=getch(), c!='s' && c!='S' && c!='n' && c!='N' );
            if(c=='s' || c=='S')
            {
                printf("Ingrese nuevo nombre:\n");
                gets(lista->nombre);
            }
            printf("Editar Direccion?\n(s/n)\n\n");
            while(c=getch(), c!='s' && c!='S' && c!='n' && c!='N' );
            if(c=='s' || c=='S')
            {
                printf("Ingrese nueva direccion:\n");
                gets(lista->direccion);
            }
            printf("Editar saldo?\n(s/n)\n\n");
            while(c=getch(), c!='s' && c!='S' && c!='n' && c!='N' );
            if(c=='s' || c=='S')
            {
                printf("Ingrese nuevo saldo:\n");
                scanf("%d",&lista->cuenta);
            }
            fflush(stdin);
            return 0;
        }
        lista=lista->sig; //sino se recorre la lista
    }
    return 1;
}
