/*
  Ejercicio # 6
  Nombre: Lista de Postres
  Autor: Carlos Rolando Calán Ajquill
  Fecha: 06/07/06 00:45
  Descripción: Programa que una lista con sublista, es decir una lista de 
               postres con sus respectivos ingredientes
  Versión: 1.0 
*/
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <ConIO.h>
#include <StdIO.h>
#include <DOS.h>
#include <String.H>
#include <CType.H>
using namespace std;

struct INFOPOSTRE
{
	char Nombre[25];	 //Nombre del postre, es la estructura principal
};
struct Ingredientes
{
	char Nombre[25];   //Ingredientes del postre	
};
struct SubLista
{
	Ingredientes Info;
	SubLista *Sig;
};
struct LISTA
{
	INFOPOSTRE Info;
	SubLista *Cab;   //Apunta a cada sublista de cada nodo de la lista principal
	LISTA *Sig;
} *CAB=NULL;
char NombreArchivo[20] = "Postres.pos";
fstream Archivo;
typedef struct INFOPOSTRE INFOPOSTRE;
typedef struct LISTA LISTA;
typedef struct InfoSubLista InfoSubLista;
typedef struct SubLista SubLista;

void ListarLISTA()
{
	if (!CAB)
		cout<<"Lista vacia \a";
	else 
  {
	  LISTA *p = CAB;
		int i=0;
		while ( p )
    {
			cout<<"\n";
      cout<<setiosflags(ios::right)<<setw(8)<<i++<< "   "
				 <<setiosflags(ios::left)<<setw(25)<<p->Info.Nombre<<"\n";
			p = p->Sig;
		}
	}
}

LISTA *InsertarLISTA(INFOPOSTRE item)
{
  LISTA *p, *q, *nuevo;
	nuevo = new(LISTA);
	if (nuevo == NULL) 
  {
		cout<<"No hay memoria suficiente";
		return(NULL);  // No insertado
	}
	p = NULL;
	q = CAB;
	while (q != NULL && strcmp(item.Nombre, q->Info.Nombre)>0)
  {
		p = q;
		q = q->Sig;
	}
	if (q && strcmp(item.Nombre, q->Info.Nombre)==0)
  {
		delete(nuevo);
		return (NULL);  // esto se hace porque esta repetido
	}
  nuevo->Info = item;
	nuevo->Sig  = q;
	nuevo->Cab  = NULL;
	if ( p == NULL)
		CAB = nuevo;      //era el primero de la lista
	else
		p->Sig = nuevo;  //"caso general"
	return(nuevo);     // insertado
}

SubLista *InsertarEnSubLista(Ingredientes item, SubLista *Cab)
{
	SubLista *p, *q, *nuevo;
	if ((nuevo = new SubLista )==NULL)
  {
		cout<<"No hay memoria suficiente";
		return NULL;
	}
	p = NULL;
	q = Cab;
	while(q != NULL && strcmp(item.Nombre, q->Info.Nombre)>0)
  {
		p = q;
		q = q->Sig;
	}
	nuevo->Info = item;
	nuevo->Sig  = q;
	if ( p == NULL)
		Cab = nuevo;  //era el primer ingrediente de la lista
	else
		p->Sig = nuevo; //"caso general"
	return(Cab);
}

void CargarLISTA_y_SubListas()
{
	INFOPOSTRE registro;
	LISTA *p;
	int n;
	Ingredientes reg;
	SubLista *Cab;
	CAB = NULL;
	Archivo.open(NombreArchivo,ios::in|ios::binary);
	if (!Archivo)
  {
		cout << "No se puede abrir el archivo \a\n";
	}
	else 
  {
		while(Archivo.read((char *)&registro, sizeof(registro)))
    {
			p = InsertarLISTA(registro);//p es puntero a donde se inserto en lista
			Archivo.read((char *)&n, sizeof(n));  //# nodos en lista enlazada
			p->Cab=NULL;
			for(int i=0; i<n; i++)
      {
				Archivo.read( (char *)&reg, sizeof(reg) );
				p->Cab = InsertarEnSubLista(reg, p->Cab);
			}
		}
		Archivo.close();
	}
}

void GrabarLISTA_y_SubListas(LISTA *P)
{ 
	SubLista *p;
	int n;
	if (P) 
  {
		Archivo.write((char *)&P->Info, sizeof(P->Info));
		p = P->Cab;
		n = 0;
		while(p) 
    { 
      n++; 
      p=p->Sig; 
    }  //Cuenta # nodos en lista enlazada
		Archivo.write((char *)&n, sizeof(n)); //Graba en disco # nodos
		p = P->Cab;
		while(p) 
    {
			Archivo.write((char *)&p->Info, sizeof(p->Info));
			p=p->Sig;
		}
		GrabarLISTA_y_SubListas(P->Sig);
	}
}

void PostreLISTA()
{
	INFOPOSTRE item;
	cout <<"\n\n Digite Informacion a Insertar en la LISTA: ";
	cout <<"\n\n Nombre del postre: ";
	gets(item.Nombre);	
	if (InsertarLISTA(item) == 0)
  {
		cout<<"\n\n Repetido \a";
		getch();
	}
}

LISTA* EncontrarLISTA(INFOPOSTRE item)
{
	LISTA *p;
	p = CAB;
	while (p && strcmp(item.Nombre,p->Info.Nombre)>0)
	  p = p->Sig;
	if(p && strcmp(item.Nombre,p->Info.Nombre)!=0 )  // No encontrado
		p= NULL;
	return p;
}

int EliminarLISTA(LISTA *p)
{
  LISTA *q;
	if (p == CAB)
	  CAB = p->Sig;      //eliminado el primer postre de la lista
	else 
  {
		q = CAB;
		while (q->Sig != p)
			q = q->Sig;
		q->Sig = p->Sig;
	}
	delete(p);
	return 1;
}

void EliminarPostreDeLaLISTA()
{
	INFOPOSTRE item;
	LISTA *LISTA;
	if (CAB == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\n Digite Nombre del postre a borrar: ";
		gets(item.Nombre);
		LISTA = EncontrarLISTA(item);
		if (LISTA)
			EliminarLISTA(LISTA);
		else 
    {
			cout<<"\n\n No se encontro el postre en lista";
			getch();
		}
	}
}

void ListarIngredientesDelPostre(SubLista *Cab)
{
	SubLista *p; 
  int Ingrediente=0;
	if (!Cab)
		cout<<"\n No tiene Ingredientes el postre \n";
	else 
  {
		p = Cab;
		while (p)
    {
			cout.setf(ios::left);
			cout<<setw(2)<<++Ingrediente<<": "<<setw(25)<<p->Info.Nombre<<"\n";			
			p = p->Sig;
		}
	}
}

void BuscarPostreEnLaLISTA()
{
	INFOPOSTRE item;
	LISTA *p;
	if (CAB == NULL)
	  cout<<"Lista de postres vacia \a";
	else
  {
		cout<<"\n\n Digite Nombre del postre a buscar: ";
		gets(item.Nombre);
		p = EncontrarLISTA(item);
		if (p)
		{
 	    cout<<"\n\n Postre encontrado en la lista: "<<item.Nombre<<"\n";			
			cout<<"\n Ingredientes del postre: \n\n ";
      ListarIngredientesDelPostre(p->Cab);			
    }
		else
			cout<<"\n\n Postre No encontrado en la lista: "<<item.Nombre ;
	}
	getch();
}

SubLista *InsertarIngredientesAlPostre(SubLista *Cab)
{
	Ingredientes item;
	cout<<"\n\n Digite el nombre del Ingrediente ";
	cout<<"\n\n Nombre: ";
	gets(item.Nombre);
	Cab = InsertarEnSubLista(item, Cab);
	if (!Cab )
  {
		cout<<"\n\n No se puede insertar se lleno la memoria\a";
		getch();
	}
	return Cab;
}

SubLista* EncontrarEnSubLista(Ingredientes item, SubLista *Cab)
{
	SubLista *p;
	p = Cab;
	while (p && strcmp(item.Nombre,p->Info.Nombre)>0)
		p = p->Sig;
	if (p && strcmp(item.Nombre,p->Info.Nombre)!=0)
		p=NULL;
	return p;
}

SubLista *EliminarEnSubLista(SubLista *p, SubLista *Cab)
{
	SubLista *q;
	if (p == Cab)
		Cab = p->Sig;   //eliminado el primer ingrediente de la lista
	else 
  {
		q = Cab;
		while (q->Sig != p)
			q = q->Sig;
		q->Sig = p->Sig;
	}
	delete(p);
	return Cab;
}

SubLista* EliminarIngredientesAlPostre(SubLista *Cab)
{
	Ingredientes item;
	SubLista *Nodo;
	if (Cab == NULL)
		cout<<"\n\n Lista vacia de Ingredientes \a";
	else
  {
		cout<<"\n\n Digite Nombre del Ingrediente a eliminar: ";
		gets(item.Nombre);
		Nodo = EncontrarEnSubLista(item, Cab);
		if (Nodo)
			Cab = EliminarEnSubLista(Nodo, Cab);
		else 
    {
			cout<<"\n\n No encontrado el ingrediente: "<<item.Nombre;
			getch();
		}
	}
	return Cab;
}

void BuscarIngredientesDelPostre(SubLista *Cab)
{
	Ingredientes item;
	SubLista *p;
	if (Cab == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\n Digite Nombre del Ingrediente a buscar:";
		gets(item.Nombre);
		p=EncontrarEnSubLista(item, Cab);
		if (p)
			cout<<"\n\n Encontrado en lista el ingrediente: "<<p->Info.Nombre;
		else
			cout << "\n\n No encontrado el ingrediente: "<<p->Info.Nombre;
	}
	getch();
}

void GrabarArchivo()
{
	Archivo.open(NombreArchivo, ios::out|ios::binary|ios::trunc);
	if (!Archivo)
		cout<<"Error en la apertura del archivo \a";
	else
  {
		GrabarLISTA_y_SubListas(CAB);
		Archivo.close();
	}
}

void AgregarIngredientes()
{
	char op;
	INFOPOSTRE item;
	LISTA *q;
	if(CAB)
  {
		system("CLS");
		cout<<"\n Ingrese el Nombre del Postre: \n ";
		cin>>item.Nombre;
		q = CAB;
		while (q && strcmp(item.Nombre, q->Info.Nombre)!=0)
		  q = q->Sig;
		if (!q)
			cout<<"\n No se encuentra ningun postre con el Nombre: "<<item.Nombre;
		else
    {
			do
      {
				system("CLS");
				cout<<"\n Estos son los ingredientes de:\t "<<q->Info.Nombre<<"\n";
				ListarIngredientesDelPostre(q->Cab);
				cout<<"\n MENU NGREDIENTES: Insertar Elminar Buscar Fin:";
				op = toupper(getch());
				switch (op)
        {
					case 'i': ;	case 'I': q->Cab=InsertarIngredientesAlPostre(q->Cab);	break;
					case 'e': ;	case 'E': q->Cab=EliminarIngredientesAlPostre(q->Cab);   break;
					case 'b': ;	case 'B': BuscarIngredientesDelPostre(q->Cab);   break;
				}
			} while (!(op == 'F' || op == 'f' ));
		}
	} 
  else
		cout<<"\n Lista de Ingredientes vacia\a";
}

int main()
{
	char op;
	system("CLS");
	CargarLISTA_y_SubListas();
	do
  {
		system("CLS");		
		cout<<"\t \t \t UNIVERSIDAD MARIANO GALVEZ \n \n"; 
    cout<<"\t \t Proyecto Final Estructura De Datos \n";    
    cout<<"\t \t Carlos Rolando Calan Ajquill    Junio/2006 \n";
    cout<<"\t \t Carne: 0910-04-13429         5to. Semestre \n";
    cout<<"\t \t ---------------------------------------------\n";    
    cout<<"\t \t \t Lista de Postres e Ingredientes \n ";
    cout<<"\t \t ---------------------------------------------\n\n";  
		cout<<"MENU PRINCIPAL: Postres Eliminar Buscar AgregarIngredientes Fin: \n";
		//ListarLISTA();
		switch (op = getch())
    {
			case 'p': ;	case 'P': PostreLISTA();	  break;
			case 'e': ;	case 'E': EliminarPostreDeLaLISTA(); 		  break;
			case 'b': ;	case 'B': BuscarPostreEnLaLISTA();	break;
			case 'a': ;	case 'A': AgregarIngredientes(); break;
		}
	} while (!(op == 'F' || op == 'f' ));
	GrabarArchivo();
}