/*
  Ejercicio # 6
  Nombre: Lista de Postres
  Autor: Carlos Rolando Calán Ajquill
  Fecha: 24/06/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 InfoIngredientes
{
	char Nombre[25];  // del postre	
};
struct INFOPOSTRE
{
	char Nombre[25];	//Nombre del postre, es la estructura principal
};
struct SubLista
{
	InfoIngredientes Info;
	SubLista *Sig;
};
struct LISTA
{
	INFOPOSTRE Info;
	SubLista *Cab;//Apunta a cada sublista desde 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;

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);  //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
}

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

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;
}

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

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

void BorrarLISTA()
{
	INFOPOSTRE item;
	LISTA *LISTA;
	if (CAB == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\nDigite Nombre del m‚dico a borrar: ";
		gets(item.Nombre);
		LISTA = EncontrarLISTA(item);
		if (LISTA)
			EliminarLISTA(LISTA);
		else {
			cout<<"\n\nNo encontrado en lista";
			getch();
		}
	}
}

void EncontrarEnLISTA(){
	INFOPOSTRE item;
	LISTA *p;
	if (CAB == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\nDigite Nombre del postre a encontrar: ";
		gets(item.Nombre);
		p = EncontrarLISTA(item);
		if (p)
			cout<<"\n\nEncontrado en lista";
		else
			cout<<"\n\nNo encontrado en lista";
	}
	getch();
}
//Para manejar cada sublista de postre
SubLista *InsertarEnSubLista(InfoIngredientes 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 primero de la lista
	else
		p->Sig = nuevo; //"caso general"
	return(Cab);
}

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

SubLista* EncontrarEnSubLista(InfoIngredientes 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;
}

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

SubLista *CapturarSubLista(SubLista *Cab)
{
	InfoIngredientes item;
	cout<<"\n\nDigite datos del postre a insertar: ";
	cout<<"\n\Nombre: ";
	gets(item.Nombre);
	Cab = InsertarEnSubLista(item, Cab);
	if ( !Cab  )
  {
		cout<<"\n\nNo se pudo insertar: se lleno la memoria\a";
		getch();
	}
	return Cab;
}

SubLista* BorrarSubLista(SubLista *Cab)
{
	InfoIngredientes item;
	SubLista *Nodo;
	if (Cab == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\nDigite Nombre de postre a borrar: ";
		gets(item.Nombre);
		Nodo = EncontrarEnSubLista(item, Cab);
		if (Nodo)
			Cab = EliminarEnSubLista(Nodo, Cab);
		else 
    {
			cout<<"\n\nNo encontrado en lista";
			getch();
		}
	}
	return Cab;
}

void EncuentraSubLista(SubLista *Cab)
{
	InfoIngredientes item;
	SubLista 	*p;
	if (Cab == NULL)
		cout<<"Lista vacia \a";
	else
  {
		cout<<"\n\nDigite Nombre de postre a encontrar:";
		gets(item.Nombre);
		p=EncontrarEnSubLista(item, Cab);
		if (p)
			cout<<"\n\nEncontrado en lista el postre"
		      <<p->Info.Nombre;
		else
			cout << "\n\nNo encontrado en lista";
	}
	getch();
}

void SubListaEnlazada(){
	char op;
	INFOPOSTRE item;
	LISTA *q;
	if(CAB)
  {
		system("CLS");
		cout<<"Nombre del Postre a encontrar y colocarle luego los ingredientes: ";
		cin>>item.Nombre;
		q = CAB;
		while (q && strcmp(item.Nombre, q->Info.Nombre)!=0)
		  q = q->Sig;
		if (!q)
			cout<<"No se encuentra ningun ingrediente" << item.Nombre;
		else
    {
			do
      {
				system("CLS");
				cout<<"Estos son los ingredientes de "<<q->Info.Nombre<< endl;
				ListarSubLista(q->Cab);
				cout<<"\nMENU DE SUBLISTA: Insertar Borrar Encontrar Terminar: ";
				op = toupper(getch());
				switch (op)
        {
					case 'i': ;	case 'I': q->Cab=CapturarSubLista(q->Cab);	break;
					case 'b': ;	case 'B': q->Cab=BorrarSubLista(q->Cab);   break;
					case 'e': ;	case 'E': EncuentraSubLista(q->Cab);   break;
				}
			} while (op != 'T');
		}
	} 
  else
		cout<<"Lista de postres vacia\a";
}
//===========================================================================
void GrabarLISTA_y_SubListas(LISTA *P)
{  // funcion recursiva
	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 Grabar()
{
	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 CargarLISTA_y_SubListas()
{
	INFOPOSTRE registro;
	LISTA *p;
	int n;
	InfoIngredientes 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();
	}
}

int main()
{
	char op;
//	unlink(NombreArch);    //Habilite si quiere borrar NombreArch
	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 Lista de Postres e Ingredientes \n ";
    cout<<"\t \t ---------------------------------------------\n\n";  
		cout<<"MENU PRINCIPAL: Postres Borrar Encontrar Ingredientes Terminar: \n";
		ListarLISTA();
		switch (op = getch())
    {
			case 'p': ;	case 'P': CapturarLISTA();	  break;
			case 'b': ;	case 'B': BorrarLISTA(); 		  break;
			case 'e': ;	case 'E': EncontrarEnLISTA();	break;
			case 'i': ;	case 'I': SubListaEnlazada(); break;
		}
	} while (!(op == 'T' || op == 't' ));
	Grabar();
}