//LISTA DE LISTAS
//El siguiente algoritmo implementa una lista simplemente enlazada en la cual
//de cada uno de sus nodos se puede desprender otra lista simplemente enlazada.
//En la lista principal se tienen nodos con la información de los médicos de una clínica
//y, en cada sublista se tiene la información de los pacientes de cada médico.
//LISTALIST.CPP
#include <IOStream.h>
#include <IOManip.h>
#include <FStream.h>
#include <ConIO.h>
#include <StdIO.h>
#include <DOS.h>
#include <String.H>
#include <CType.H>

char NombreArch[20] = "Citas.Dr";
fstream Archivo;

typedef struct INFOMEDICO INFOMEDICO;
typedef struct LISTA LISTA;
typedef struct InfoSubLista InfoSubLista;
typedef struct SubLista SubLista;

struct InfoCitas{
	char Horario[20];
	char Nombre[25];  // del paciente
	char Telefono[10];
};

struct SubLista{
	InfoCitas Info;
	SubLista *Sig;
};

struct INFOMEDICO{
	char Nombre[25]; //permite hasta 24 caracteres
	char  Telefono[10];
	float ValorHora;
};

struct LISTA{
	INFOMEDICO Info;
	SubLista *Cab;//Apunta a cada sublista desde cada nodo de la lista principal
	LISTA *Sig;
} *CAB=NULL;

LISTA *InsertarLISTA (INFOMEDICO 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(INFOMEDICO 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 vac¡a \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
				 << setiosflags(ios::right) << setw(3) << p->Info.Telefono
				 << setiosflags(ios::right | ios::showpoint | ios::fixed)
				 << setprecision(2) << setw(15) << p->Info.ValorHora <<  endl;
			p = p->Sig;
		}
	}
}

void CapturarLISTA(){
	INFOMEDICO item;

	cout << "\n\nDigite Info a InsertarLISTA: ";
	cout << "\n\Nombre del m‚dico: ";
	gets(item.Nombre);
	cout << "\n\nTel‚fono: "; 	cin >> item.Telefono;
	cout << "\n\nHonorarios por hora: "; 	cin >> item.ValorHora;
	if ( InsertarLISTA(item) == 0 ){
		cout << "\n\nRepetido \a";
		getch();
	}
}

void BorrarLISTA(){
	INFOMEDICO item;
	LISTA *LISTA;

	if (CAB == NULL)
		cout << "Lista vac¡a \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(){
	INFOMEDICO item;
	LISTA *p;

	if (CAB == NULL)
		cout << "Lista vac¡a \a";
	else{
		cout << "\n\nDigite Nombre del m‚dico a encontrar: ";
		gets(item.Nombre);
		if (p = EncontrarLISTA(item))
			cout << "\n\nEncontrado en lista y tiene el tel‚fono "<< p->Info.Telefono;
		else
			cout << "\n\nNo encontrado en lista";
	}
	getch();
}
// ===========================================================================
//         A CONTINUACION LAS FUNCIONES PARA MANEJAR CADA SubLista
// ===========================================================================
SubLista *InsertarEnSubLista (InfoCitas 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(InfoCitas 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 Cliente=0;

	if (!Cab)
		cout << "No tiene citas \a\n";
	else {
		p = Cab;
		while ( p ){
			cout.setf(ios::left);
			cout << setw(2) << ++Cliente << ": "<< setw(25) <<p->Info.Nombre;
			cout << setw(15) <<p->Info.Telefono;
			cout << setw(20) <<p->Info.Horario << endl;
			p = p->Sig;
		}
	}
}

SubLista *CapturarSubLista(SubLista *Cab){
	InfoCitas item;

	cout << "\n\nDigite datos del paciente a insertar: ";
	cout << "\n\Nombre: ";
	gets(item.Nombre);
	cout << "\n\nTelefono: ";
	cin >> item.Telefono;
	cout << "\n\Horario de la cita: ";
	gets(item.Horario);

	Cab = InsertarEnSubLista(item, Cab);
	if ( !Cab  ){
		cout << "\n\nNo se pudo insertar: se llen¢ la memoria\a";
		getch();
	}
	return Cab;
}

SubLista* BorrarSubLista(SubLista *Cab){
	InfoCitas item;
	SubLista *Nodo;

	if (Cab == NULL)
		cout << "Lista vac¡a \a";
	else{
		cout << "\n\nDigite Nombre de paciente a borrar su cita: ";
		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){
	InfoCitas item;
	SubLista 	*p;

	if (Cab == NULL)
		cout << "Lista vac¡a \a";
	else{
		cout << "\n\nDigite Nombre de paciente a encontrar: ";
		gets(item.Nombre);
		if (p=EncontrarEnSubLista(item, Cab))
			cout << "\n\nEncontrado en lista y tiene el tel‚fono "
					 << p->Info.Telefono;
		else
			cout << "\n\nNo encontrado en lista";
	}
	getch();
}

void SubListaEnlazada(){
	char op;
	INFOMEDICO item;
	LISTA *q;

	if(CAB){
		clrscr();
		cout << "Nombre del M‚dico a encontrar y colocarle luego las citas: ";
		cin >> item.Nombre;
		q = CAB;
		while (q && strcmp(item.Nombre, q->Info.Nombre)!=0)
				q = q->Sig;

		if (!q)
			cout << "No se encuentra ninguna persona de Nombre " << item.Nombre;
		else{
			do{
				clrscr();
				cout << "Estos son los pacienticos de " << q->Info.Nombre << endl;
				ListarSubLista(q->Cab);
				cout<< "\nMENU DE SUBLISTA: Insertar Borrar Encontrar Terminar: ";
				op = toupper(getch());
				switch (op){
					case 'I': q->Cab=CapturarSubLista(q->Cab);	break;
					case 'B': q->Cab=BorrarSubLista(q->Cab);   break;
					case 'E': EncuentraSubLista(q->Cab);   break;
				} //switch
			} while (op != 'T');
		}
	} else
		cout << "Lista de m‚dicos vac¡a\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(NombreArch, 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(){
	INFOMEDICO registro;
	LISTA *p;
	int n;
	InfoCitas reg;
	SubLista *Cab;

	CAB = NULL;
	Archivo.open(NombreArch,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 main(){
	char op;
//	unlink(NombreArch);    //Habilite si quiere borrar NombreArch
	clrscr();
	CargarLISTA_y_SubListas();
	do{
		clrscr();
		ListarLISTA();
		cout << "\n\nMENU PRINCIPAL: Medicos  Borrar  Encontrar  Citas Terminar: ";
		switch ( op = getch() ){
			case 'm': ;	case 'M': CapturarLISTA();	  break;
			case 'b': ;	case 'B': BorrarLISTA(); 		  break;
			case 'e': ;	case 'E': EncontrarEnLISTA();	break;
			case 'c': ;	case 'C': SubListaEnlazada(); break;
		}
	} while (!(op == 'T' || op == 't' ));
	Grabar();
}
