#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void bildschirm_leeren(void);
void menue(void);
void warte(void);
void datensatz_anlegen(void);
void datensatz_eingeben(void);
void naechster_datensatz(void);
void vorheriger_datensatz(void);
void datensatz_ausgeben(void);
void alles_ausgeben(void);
void suchen(void);
void sortieren(void);
void bubblesort_details(int);
void datensatz_loeschen(void);
void alles_loeschen(void);

struct M_Student {
	char nachname[16+1];
	char vorname[16+1];
	char wohnort[16+1];
	int  index; /* wird beim Sortieren neu indiziert */
	struct M_Student *davor;
	struct M_Student *danach;
};

typedef struct M_Student T_Student;

T_Student *dvl_anf = NULL; /* Zeiger auf DVL-Anfang */
T_Student *dvl_end = NULL; /* Zeiger auf DVL-Ende */
T_Student *dvl_akt = NULL; /* Zeiger auf aktuellen DS */

int MAXIDX=80; /* maximal erlaubter Index:80 */
int MAXANZ=40; /* maximal 40 Studierende */
int ANZAHL=0;

int main (void) {
	char wahl = '1', ignorier;

	while(wahl != '0') {
		menue();
		fflush(stdin);
		wahl = getchar();
		ignorier = getchar();

		switch (wahl) {
			case '1':	datensatz_eingeben();
						break;
			case '2':	datensatz_ausgeben();
						break;
			case '3':	alles_ausgeben();
						break;
			case '4':	vorheriger_datensatz();
						break;
			case '5':	naechster_datensatz();
						break;
			case '6':	suchen();
						break;
			case '7':	sortieren();
						break;
			case '8':	datensatz_loeschen();
						break;
			case '9':	alles_loeschen();
						break;
			case '0':	exit(0);
						break;
			default :	printf("\n\nFalsche Eingabe!");
						warte();
		}
	}

	return 0;
}


void menue(void) {
	bildschirm_leeren();
	printf("\nWillkommen bei der simplen Studenten-Datenbank");
	printf("\n\nAnzahl Datensaetze: %2i", ANZAHL);
	if (dvl_akt != NULL)
		printf(" | hoechster Index: %2i | aktueller Index: %2i", dvl_end->index, dvl_akt->index);
	printf("\n\nBitte waehlen Sie:");
	printf("\n\t(1)  neuen Datensatz hinzufuegen");
	printf("\n\t(2)  aktuellen Datensatz anzeigen");
	printf("\n\t(3)  alle Datensaetze anzeigen");
	printf("\n\t(4)  vorheriger Datensatz");
	printf("\n\t(5)  naechster Datensatz");
	printf("\n\t(6)  Suchen");
	printf("\n\t(7)  Sortieren");
	printf("\n\t(8)  aktuellen Datensatz loeschen");
	printf("\n\t(9)  alle Daten loeschen");
	printf("\n\n\t(0)  Programm beenden");
	printf("\n\n\nIhre Wahl: ");
	fflush(stdout);
	return;
}

void warte(void) {
	int z;

	printf("\n\n\n\t ---> ENTER");
	fflush(stdout);
	fflush(stdin);
	z = getchar();
	z++;
	return;
}

void bildschirm_leeren(void) {
	system("@cls||clear");
	return;
}

void datensatz_anlegen(void) {
	dvl_akt = (T_Student *) malloc(sizeof(T_Student));

	if (dvl_end != NULL)
		dvl_akt->index = dvl_end->index + 1;
	else
		dvl_akt->index = 1;

	ANZAHL++;

	dvl_akt->danach = NULL;
	dvl_akt->davor  = dvl_end;

	if (dvl_anf == NULL)
		dvl_anf = dvl_akt;
	else
		dvl_end->danach = dvl_akt;

	dvl_end = dvl_akt;

	return;
}

void datensatz_eingeben(void) {
	bildschirm_leeren();
	if ((dvl_end != NULL) && ((dvl_end->index >= MAXIDX) || (ANZAHL >= MAXANZ))) {
		if (dvl_end->index >= MAXIDX)
			printf("\n\tDie hoechste erlaubte Index (%i) wurde erreicht.\n", MAXIDX);
		if (ANZAHL >= MAXANZ)
			printf("\n\tDie maximal erlaubte Anzahl Datensaetze (%i) wurde erreicht.\n", MAXANZ);
	}
	else {
		datensatz_anlegen();
		bildschirm_leeren();
		printf("\n\tEingabe eines Datensatzes\n");

		printf("\tNachname: ");
		fflush(stdout);
		fflush(stdin);
		/* im Folgenden gets() um auch Leerzeichen einlesen zu koennen */
		gets(dvl_akt->nachname);

		printf("\tVorname:  ");
		fflush(stdout);
		fflush(stdin);
		gets(dvl_akt->vorname);

		printf("\tWohnort:  ");
		fflush(stdout);
		fflush(stdin);
		gets(dvl_akt->wohnort);
	}
	warte();
	return;
}

void datensatz_ausgeben() {
	bildschirm_leeren();
	if (dvl_akt != NULL) {
		printf("\n\tNachname: %-16s", dvl_akt->nachname);
		printf("\n\tVorname:  %-16s", dvl_akt->vorname);
		printf("\n\tWohnort:  %-16s", dvl_akt->wohnort);
		fflush(stdout);
	}
	else
		printf("\n\tAktuell ist kein Datensatz indiziert.");
	warte();
	return;
}

void alles_ausgeben(void) {
	T_Student *dvl_tmp;
	dvl_tmp	= dvl_akt;
	bildschirm_leeren();

	if (dvl_anf != NULL) {
		printf("\nIndex  Nachname        Vorname         Wohnort");
	
		dvl_akt = dvl_anf;

		while(dvl_akt != NULL) {
			if (dvl_akt == dvl_tmp)
				printf("\n* ");
			else
				printf("\n  ");
			printf("%2i     ", dvl_akt->index);
			printf("%-16s", dvl_akt->nachname);
			printf("%-16s", dvl_akt->vorname);
			printf("%-16s", dvl_akt->wohnort);
			fflush(stdout);
			dvl_akt = dvl_akt->danach;
		}
		
		dvl_akt = dvl_tmp;
	}
	else
		printf("\n\tAktuell ist kein Datensatz indiziert.");
	warte();
	return;
}

void naechster_datensatz(void) {
	if (dvl_anf == NULL) return;

	if (dvl_akt != dvl_end)
		dvl_akt = dvl_akt->danach;
	else {
		bildschirm_leeren();
		printf("\n\tDas Ende der Datensatzkette wurde bereits erreicht.");
		warte();

		/*
		 * Variante mit geschlossener Kette (d.h. als Ring):
		 * dvl_akt = dvl_anf;
		 */

	 }
	return;
}

void vorheriger_datensatz(void) {
	if (dvl_anf == NULL) return;

	if (dvl_akt != dvl_anf)
		dvl_akt = dvl_akt->davor;
	else {
		bildschirm_leeren();
		printf("\n\tDer Kopf der Datensatzkette wurde bereits erreicht.");
		warte();

		/*
		 * Variante mit geschlossener Kette (d.h. als Ring):
		 * dvl_akt = dvl_end;
		 */

	 }
	return;
}

void suchen(void) {
	char suchwort[16+1];
	int gefunden = 0;

	bildschirm_leeren();

	if (dvl_akt != NULL) {
		printf("\n\tSuchen nach Nachnamen oder Teilen davon");
		printf("\n\t(Index wird erster Treffer, sonst Ende der Datenbank)\n");

		printf("\n\tNachname: ");
		fflush(stdout);
		fflush(stdin);
		/* im Folgenden gets() um auch Leerzeichen einlesen zu koennen */
		gets(suchwort);

		dvl_akt = dvl_anf;
		while (dvl_akt) {
			if (strstr(dvl_akt->nachname, suchwort)) {
				gefunden = 1;
				break;
			}
			dvl_akt = dvl_akt->danach;
		}
		if (gefunden) {
			printf("\n\tEs gibt einen Treffer bei Index %i.", dvl_akt->index);
			warte();
			datensatz_ausgeben();
			return;
		}
		else
			printf("\n\tEs gab keinen Treffer. Der Index ist am Ende der Datenbank.");
	}
	else
		printf("\n\tAktuell ist kein Datensatz indiziert.");
	warte();
	return;
}

void sortieren(void) {
	/* Bubblesort */
	T_Student *z1=dvl_anf, *z2, *z3;
	int tausch;

	bildschirm_leeren();

	if (dvl_anf != dvl_end) {
		printf("\nBeginne mit Bubblesort...\n");
		while (z1 != dvl_end) {
			tausch = 0;
			z2 = dvl_end;

			while (z2 != z1) {
				bubblesort_details(z2->index);
				z3 = z2->davor;
				printf("\nVergleiche %s mit %s. Ergebnis: ", z2->nachname, z3->nachname);
				switch(strcmp((z2->nachname), (z3->nachname))) {
					case -1:	printf("vertauschen"); break;
					case 0:		printf("nichts tun (identisch)"); break;
					case 1:		printf("nichts tun (bereits sortiert)"); break;
				}
				printf("\n--------------------------------------------------------\n");
				if (strcmp((z2->nachname), (z3->nachname)) < 0) {
					if (z3 == z1)
						z1 = z2;
					tausch++;

					if (z3->davor)
						(z3->davor)->danach = z2;
					else
						dvl_anf = z2;

					if (z2->danach)
						(z2->danach)->davor = z3;
					else
						dvl_end = z3;

					z2->davor  = z3->davor;
					z3->davor  = z2;
					z3->danach = z2->danach;
					z2->danach = z3;
					z2         = z3;
				}
				z2 = z2->davor;
			}
			if (tausch == 0)
				break;
			z1 = z1->danach;
		}
		dvl_akt = dvl_anf;
		printf("\n\tDie Datensaetze wurden alphabetisch aufsteigend nach Nachnamen sortiert.");
		z1 = dvl_anf;
		tausch = 1;
		do {
			z1->index = tausch;
			tausch++;
			z1 = z1->danach;
		} while (z1);
		printf("\n\tDie Indizes wurden neu angelegt.");
	}
	else
		printf("\n\tZum Sortieren muessen mindestens zwei Datensaetze indiziert sein.");
	warte();
	return;
}

void datensatz_loeschen(void) {
	int zustand = 0;
	bildschirm_leeren();

	if (dvl_anf == NULL)
		printf("\n\tAktuell ist kein Datensatz indiziert.");
	else {
		printf("\n\tLoesche Datensatz mit Index %i... ", dvl_akt->index);

		if (dvl_akt->davor)
			(dvl_akt->davor)->danach = dvl_akt->danach; 
		else {
			dvl_anf = dvl_akt->danach;
			zustand = 1;
		}

		if (dvl_akt->danach) {
			(dvl_akt->danach)->davor = dvl_akt->davor;
			zustand = (zustand == 1);
		}
		else
			dvl_end = dvl_akt->davor;

		switch(zustand) {
			case 0:	dvl_akt = dvl_akt->davor;
					break;
			case 1:	dvl_akt = dvl_akt->danach;
					break;
		}

		ANZAHL--;

		/*
		 * Variante mit Speicher-Freigabe und Zurückspulen auf Anfang:
		 * free(dvl_akt);
		 * dvl_akt = dvl_anf;
		 */

		printf("Erledigt.");
	}
	warte();
	return;
}

void alles_loeschen(void) {
	bildschirm_leeren();
	if (dvl_anf == NULL)
		printf("\n\tDie Datenbank war schon leer.");
	else {
		/*
		 * Variante mit Speicher-Freigabe:
		 *	do {
		 *		dvl_akt = dvl_end;
		 *		dvl_end = dvl_end->davor;
		 *		free(dvl_akt);
		 *	} while(dvl_end);
		 */
		dvl_anf = NULL;
		dvl_end = NULL; /* nicht benötigt, falls Speicher-Freigabe erfolgt! */
		dvl_akt = NULL;
		ANZAHL = 0;
		printf("\n\tDie Datenbank wurde geleert.");
	}
	warte();
	return;
}

void bubblesort_details(int aktuellerIndex) {
	printf("\nIndex  Nachname        Vorname         Wohnort");
	dvl_akt = dvl_anf;
	while(dvl_akt != NULL) {
		if (aktuellerIndex == dvl_akt->index)
			printf("\n* ");
		else
			printf("\n  ");
		printf("%2i     ", dvl_akt->index);
		printf("%-16s", dvl_akt->nachname);
		printf("%-16s", dvl_akt->vorname);
		printf("%-16s", dvl_akt->wohnort);
		fflush(stdout);
		dvl_akt = dvl_akt->danach;
	}
	printf("\n");
	return;
}
