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

struct aluno
{
  int codigo;
  char nome[50];
  char curso[35];
};

struct listaAluno
{
  struct aluno aluno;
  struct listaAluno *proximo;
  struct listaLivro *inicLivro;
};

struct livro
{
	int codigo;
	char titulo[50];
	char autor[40];
};

struct listaLivro
{
	struct livro info;
	struct listalivro *proximo;
};

/*
 * Estrutura do tipo aluno primária
 */
struct listaAluno* insereInicio(struct listaAluno *inicio, struct aluno x){
	struct listaAluno *aux;
  	aux = (struct listaAluno*)malloc(sizeof(struct listaAluno));
  	aux->aluno = x;
  	aux->proximo = inicio;
  	inicio = aux;
  	return inicio;
}

struct listaAluno* removeInicio(struct listaAluno *inicio){
  	struct listaAluno *aux;
  	aux = inicio;
  	inicio = inicio->proximo;
  	free(aux);
  	return inicio;
}

void insereDepois(struct listaAluno *l, struct aluno x){
  	struct listaAluno *aux;
  	aux=(struct listaAluno*)malloc(sizeof(struct listaAluno));
  	aux->aluno = x;
  	aux->proximo = l->proximo;
  	l->proximo = aux;
}

void removeDepois(struct listaAluno *l){
  	struct listaAluno *aux;
  	aux = l->proximo;
  	l->proximo = aux->proximo;
  	free(aux);
}

struct listaAluno* insereOrdenado(struct listaAluno *inicio, struct aluno x)
{
  	struct listaAluno *p, *q;
  	p = inicio;
  	if((p == NULL) || (x.codigo < p->aluno.codigo))
	{
   		inicio = insereInicio(inicio , x);
    	return inicio;
  	}
  	
	  q = p;
  	
	while((q != NULL) && (q->aluno.codigo < x.codigo))
	{
    	p = q;
    	q = p->proximo;
  	}
  	if((q == NULL) || (q->aluno.codigo > x.codigo))
    	insereDepois(p, x);
  	else
   		printf("\nAluno já cadastrado");
    return inicio;
}

struct listaAluno* removeOrdenado(struct listaAluno *inicio, int x)
{
  	struct listaAluno *p, *q;
  	p = inicio;
  	
  	if(p == NULL)
	{
	    printf("\nLista vazia\n");
	    getchar();
    	return inicio;
  	}
  	
  	if(x == p->aluno.codigo)
	{
    inicio = removeInicio(inicio);
    return inicio;
  	}
  	
  	q = p;
  	
  	while((q != NULL) && (q->aluno.codigo < x))
	{
    	p = q;
    	q = p->proximo;
  	}
  	
  	if((q != NULL) && (q->aluno.codigo == x))
   		removeDepois(p);
  	else 
	{
    	printf("\nAluno não Cadastrado");
    	getchar();
  	}   
  	
  	return inicio;
}

/* 
 * Cria uma struct do tipo estudante, para posteriormente 
 * ordenar os alunos.
 */
struct aluno criaAluno(char nome[50], int cod, char curso[35])
{
	struct aluno estudante;
	
	estudante.codigo = cod;
	strcpy(estudante.nome, nome);
	strcpy(estudante.curso, curso);
	
	return estudante;
}
/* 
 * Entrada de dados para definir os valores do aluno, 
 * chama (criaAluno) para fazer a struct e (insereOrdenado)
 * para criar a struct de listaAluno.
 */
struct listaAluno* incluiAluno(struct listaAluno *inicio)
{
	char nome[50], curso[35];
	int codigo, cont, esc;
	
	cont = 0;
	while(cont == 0){
		
		printf("Cadastro de alunos\n");
		printf("Nome Completo: ");
		scanf("%s", &nome);
		printf("Código: ");
		scanf("%i", &codigo);
		printf("Curso:");
		scanf("%s", &curso);	
		
		inicio = insereOrdenado(inicio, criaAluno(nome, codigo, curso));
		
		printf("Deseja cadastrar outro aluno? (1 SIM | 2 NÃO): ");
		scanf("%i", &esc);
		
		if(esc == 2)
			cont = 1;
	}
	return inicio;
}
/* 
 * Exclui aluno cadastro atraves de um código informado, 
 * Caso o aluno possuir livros em sua conta, o mesmo não
 * pode ser excluido.
 * OBS. BUG -> loop infinito, não estou achando o erro.
 */
struct listaAluno* removeAluno(struct listaAluno *inicio)
{
	struct listaAluno *aux;
	int cod_aluno;
	
	printf("Excluir Aluno\n");
	printf("Informe o Código:");	
	scanf("%i", &cod_aluno);
	
	aux = inicio;
	while(aux != NULL)
	{
		if((cod_aluno == aux->aluno.codigo)&&(aux->inicLivro != NULL))
			inicio = removeOrdenado(inicio, cod_aluno);
		else
			printf("O aluno não pode ser removido, pois possui livros em sua conta.");
 	}		
 	return inicio;
}
/* 
 * Exibe todos os alunos cadastrados no sistema.
 */
void mostraAlunos(struct listaAluno *inicio)
{
	struct listaAluno *aux;
	aux = inicio;
	
	if(aux == NULL)
		printf("Nenhum aluno cadastrado.");
 	else
 	{
 		printf("Lista de alunos cadastrados:\n");
		while(aux != NULL)
		{
		 	printf("Código: %d | Nome: %s | Curso: %s\n", aux->aluno.codigo, aux->aluno.nome, aux->aluno.curso);
			aux = aux->proximo;
		}
	}
}
/* 
 * A partir de um código, procura o aluno no sistema
 * e exibe caso o encontre.
 * OBS. BUG -> Caso haja alunos cadastrados no sistema,
 * mas o código informado não seja de nenhum mensagem do ultimo
 * IF não é exibida.
 */
void buscaAluno(struct listaAluno *inicio)
{
	struct listaAluno *aux;
	int cod_aluno;
	int cot;
	
	cot = 0;
	aux = inicio;
	
		if(aux == NULL)
	{
		printf("Não há alunos cadastrados no sistema.");
		printf("\nImpossivel realizar consulta.");
	}
	else
	{
		printf("\nLocalizar Aluno\n");
		printf("Informe o código do aluno: ");
		scanf("%i", &cod_aluno);
		
	 	while(aux != NULL)
		{ 
	 		if(cod_aluno == aux->aluno.codigo)
			{
	 			printf("\nCódigo: %d | Nome: %s | Curso: %s",  aux->aluno.codigo, aux->aluno.nome, aux->aluno.curso);
			 	cot = 1;
	    	}	
			aux = aux->proximo;
		}
	}
	
  	if((aux != NULL)&&(cot == 0))
  	{
    	printf("O código informado não pertece a nenhum aluno cadastrado no sistema.");
	}
}

/*
 * Estrutura do tipo livro primária
 */
struct listaLivro* insereInicioLivro(struct listaLivro *inicio, struct livro x){
	struct listaLivro *aux;
  	aux = (struct listaLivro*)malloc(sizeof(struct listaLivro));
  	aux->info = x;
  	aux->proximo = inicio->proximo;
  	inicio = aux;
  	return inicio;
}

struct listaLivro* removeInicioLivro(struct listaLivro *inicio){
  	struct listaLivro *aux;
  	aux = inicio;
  	inicio->proximo = inicio->proximo;
  	free(aux);
  	return inicio;
}

void insereDepoisLivro(struct listaLivro *l, struct livro x){
  	struct listaLivro *aux;
  	aux=(struct listaLivro*)malloc(sizeof(struct listaLivro));
  	aux->info = x;
  	aux->proximo = l->proximo;
  	l->proximo = aux->proximo;
}

void removeDepoisLivro(struct listaLivro *l){
  	struct listaLivro *aux;
  	aux->proximo = l->proximo;
  	l->proximo = aux->proximo;
  	free(aux);
}

struct listaLivro* insereOrdenadoLivro(struct listaLivro *inicio, struct livro x){
  	struct listaLivro *p, *q;
  	
	p = inicio;
  	
	if((p == NULL) || (x.codigo < p->info.codigo)){
    	inicio = insereInicioLivro(inicio, x);
    	return inicio;
  	}
  	
  	q = p;
  
  	while((q != NULL) && (q->info.codigo < x.codigo)){
    	p = q;
    	q->proximo = p->proximo;
  	}
  	
  	if((q == NULL) || (q->info.codigo > x.codigo))
    	insereDepoisLivro(p, x);
  	else
    	printf("\nElemento já Existe");
    	
    return inicio;
}

struct listaLivro* removeOrdenadoLivro(struct listaLivro *inicio, struct livro x){
  	struct listaLivro *p, *q;
  	p = inicio;
  	
  	if(p == NULL){
	    printf("\nLista vazia\n");
	    getchar();
    return inicio;
  	}
  	
  	if(x.codigo == p->info.codigo){
    inicio = removeInicioLivro(inicio);
    return inicio;
  	}
  	
  	q = p;
  	
  	while((q != NULL) && (q->info.codigo < x.codigo)){
    	p = q;
    	q->proximo = p->proximo;
  	}
  	
  	if((q != NULL) && (q->info.codigo == x.codigo))
   		removeDepoisLivro(p);
  	else {
    	printf("\nElemento nao Cadastrado");
    	getchar();
  	}   
  	
  	return inicio;
}

/*
 * Inicio da criação de livros e inicio dos principais erros
 */

/* 
 * Cria a estrutura de dados do tipo Livro 
 */
struct livro criaLivro(char titulo[50], int cod, char autor[40])
{
	struct livro l;
	
	l.codigo = cod;
	strcpy(l.autor, autor);
	strcpy(l.titulo, titulo);
	
	return l;
}
/* 
 * Entrada de dados para definir os valores do aluno, 
 * verifica se determinado aluno existe, 
 * caso exista chama (insereOrdenado) passando como referencia 
 * (auxLivro[inicio do livro]) e (criaLivro[para criar a estrutura do tipo Livro]);
 */
struct listaAluno* incluiLivro(struct listaAluno* inicio)
{
	struct listaAluno *auxAluno;
	struct listaLivro *auxLivro;
	char autor[40], titulo[50];
	int codigo, cod_aluno, cont;
		
	cont = 0;
	auxAluno = inicio;
	auxLivro = inicio->inicLivro;
	
	printf("\nIncluir livro\n");
	printf("Informe o código do aluno: ");
	scanf("%i", &cod_aluno);
	
	if(auxAluno == NULL)
	{
		printf("Nenhum aluno cadastrado no sistema.");
	}
	else
	{
	 	while(auxAluno != NULL)
		{ 
	 		if(cod_aluno == auxAluno->aluno.codigo)
			{
				printf("\Dados do livro\n");
				printf("Código: ");
				scanf("%i", &codigo);
				printf("Título: ");
				scanf("%s", &titulo);
				printf("Autor:");
				scanf("%s", &autor);
				auxLivro = insereOrdenadoLivro(auxLivro, criaLivro(titulo, codigo, autor));
				auxAluno->inicLivro = auxLivro;
			 	cont = 1;
	    	}	
		}
	}
	
  	if((auxAluno != NULL)&&(cont == 0))
  	   	printf("O código informado não pertece a nenhum aluno cadastrado no sistema.");
}

main() 
{
	setlocale(LC_ALL, "Portuguese");
	struct listaAluno *inicio = NULL;
	int opcAluno, exitMenu, opcLivro;
	int cod_aluno, cod_livro;
	
	// MENU 
	while (exitMenu == 0)
	{
		printf("1: Incluir Aluno");
		printf("\n5: Incluir Livro");
		printf("\n4: Buscar Aluno");
		printf("\n3: Exibir Alunos");
		printf("\n6: Exibir Livros do Aluno");
		printf("\n2: Excluir Aluno");
		printf("\n7: Excluir Livro do Aluno");
		printf("\n8: Bônus -> Excluir ultimo aluno");
		printf("\n9: Sair");
		printf("\n\nO que deseja fazer: ");
		scanf("%d", &opcAluno);
		printf("\n");
		switch(opcAluno)
		{
			case 1:
		   		inicio = incluiAluno(inicio);
		     	break;
		    	
			case 2:
				removeAluno(inicio);
				break;
				
			case 3:
				mostraAlunos(inicio);
				break;
					
			case 4:
				buscaAluno(inicio);
				break;
			
			case 5:
				incluiLivro(inicio);
				break;
				
			case 9:
				exitMenu = 1;
				break;
				
			default :
       			printf ("Valor invalido!");
		}
		
		if(exitMenu == 1)
			printf("Operação terminada.");
		else
			printf("\n\n");
	}
	
}