/**************************************************************************

                         Denne filen er en del av
                           EXEC's store C-kurs

                              Programmert av 
                    Ørjan Eriksen og Torstein Pettersen

                          database.c   leksjon 4 
  
**************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <string.h>
#include <stdio.h>

#include "base.h"

/* eksterne funksjoner fra hentlagre.c */

extern void lagre_liste(struct Liste *);
extern void hent_liste(struct Liste **,struct Liste **);

/* globale funksjoner tilgjengelig utenfor denne modulen */

void sett_inn_post(struct Liste **,struct Liste **,struct Liste *);

/* lokale funksjoner tilgjengelig kun for denne modulen */

static void vent();
static int mystrcmp(UBYTE *,UBYTE *);
static void legg_inn_data(struct Liste *);
static struct Liste *finn_post(struct Liste *);
static void fjern_post(struct Liste **,struct Liste **);
static void slett_alt(struct Liste *);
static void ny_post(struct Liste **,struct Liste **);
static void Endre_post(struct Liste **,struct Liste **);
static void plukk_ut_post(struct Liste **,struct Liste **,struct Liste *);

/* diverse lokale variabler */

static struct Liste *lhode = NULL;		/* starten på listen */
static struct Liste *lslutt = NULL;		/* siste post i listen */

/************************************************************************/
/* Spesial strcmp for norske 'æ', 'ø' og 'å'.
   Denne rutinen sammenligner to tekst strenger og gir følgende resultat :
		str1 > str2  -> positivt
		str1 < str2  -> negativt
		str1 = str2  -> 0
*/

static int mystrcmp(str1,str2)
register UBYTE *str1,*str2;
{
	register short s1,s2;
	register UBYTE c1,c2;
	
	while (*str1) {
		c1 = *str1; /* plukk ut et tegn fra tekst 1 */
		c2 = *str2; /* plukk ut et tegn fra tekst 2 */
		s1 = (short)c1; /* gjør tegn 1 om til short */
		s2 = (short)c2; /* gjør tegn 2 om til short */

		if (c1 == 'Å' || c1 == 'å') /* hvis tegn 1 er 'å' øk s1 med 100 */
			s1 += 100;
		if (c2 == 'Å' || c2 == 'å') /* hvis tegn 2 er 'å' øk s2 med 100 */
			s2 += 100;

/* sjekk om de er forskjellig */
		if (s1-s2)
			return(s1-s2); /* returner differansen hvis de er forskjellig */
		str1++; /* øk begge tekst peker med 1 for å sjekke neste tegn */
		str2++;
	}

	return(0); /* hvis tekstene er like returneres 0 */
}

/****************** her starter de globale funksjonene ******************/

/* denne rutinen legger inn de nye postenen i riktig rekkefølge */

void sett_inn_post(lhd,lsl,pst)
struct Liste **lhd;
struct Liste **lsl;
register struct Liste *pst;
{
	register struct Liste *crt;

	if (pst == NULL)
		return;

	crt = *lhd;

	if (crt == NULL) {
		*lhd = pst;
		*lsl = pst;
		return;
	}
	else {
		while (crt){
			if (mystrcmp(crt->Navn,pst->Navn) < 0)
				crt = crt->neste;
			else
				break;
		}
		if (crt == *lhd) {
			crt->forrige = pst;
			pst->neste = crt;
			*lhd = pst;
		}
		else if (crt) {
			pst->neste = crt;
			pst->forrige = crt->forrige;
			crt->forrige->neste = pst;
			crt->forrige = pst;
		}
		else if (crt == NULL) {
			pst->forrige = *lsl;
			pst->forrige->neste = pst;
			*lsl = pst;
		}
	}
}

/****************** her starter de lokale funksjonene ******************/

/* rutine for å vente på return */

static void vent()
{
	printf("\n\n\x1b[33;42m Press RETURN for hovedmeny! \x1b[0m");
	getchar();
}

/************************************************************************/
/* denne rutinen tømmer hele listen */

static void slett_alt(hode)
register struct Liste *hode;
{
	register struct Liste *lst,*dummy;

	lst = hode;

	while (lst) {
		dummy = lst->neste;
		FreeMem(lst,LLENGDE);
		lst = dummy;
	}
}

/************************************************************************/
/* denne rutinen leser data inn i en post */

static void legg_inn_data(pst)
struct Liste *pst;
{
 	char dummy[80];

	printf("\f\x1b[3;0H\x1b[JSkriv Inn data for personen \n\n");

	printf("Navn......: ");
	gets(dummy);
	dummy[29] = '\0';
	strcpy(pst->Navn,dummy);

	printf("Adresse...: ");
	gets(dummy);
	dummy[29] = '\0';
	strcpy(pst->Adresse,dummy);

	printf("Post Nr...: ");
	gets(dummy);
	dummy[5] = '\0';
	strcpy(pst->PostNr,dummy);

	printf("Post Sted : ");
	gets(dummy);
	dummy[19] = '\0';
	strcpy(pst->PostSted,dummy);

	printf("Telefon Nr: ");
	gets(dummy);
	dummy[9] = '\0';
	strcpy(pst->Telefon,dummy);
}

/************************************************************************/
/* denne rutinen skriver ut alle poster med navn og telefon nr */

static void vis_poster(lhd)
struct Liste *lhd;
{
	register struct Liste *p;

	p = lhd; /* peker til første post */

/* \f tømmer alt som er i CLI vinduet */
	printf("\f|            Navn               |  Telefon\n"); /* overskrift */
	printf("|-------------------------------|-----------\n");

	while (p) {
/*
  Vi setter av 30 tegn til navnet slik at vi får en brukbar justering
  av teksten. Hvis vi ikke bruker -30 vil teksten bli høyrejustert i
  et felt på 30 tegn, minusen sørger for at teksten bli venstrjustert.
*/
		printf("| %-30s| %s\n",p->Navn,p->Telefon); /* skriv ut Navn og telefon nr */
		p = p->neste;								/* hopp til neste post */
	}
}

/************************************************************************/
/* denne rutinen skriver ut innholdet i en post */

static void vis_post(post)
struct Liste *post;
{
	if (!post)
		return;
	printf("\x1b[3;0H\x1b[J\nData for en person:\n\n");
	printf("Navn......: %s\n",post->Navn);
	printf("Adresse...: %s\n",post->Adresse);
	printf("Post Nr...: %s\n",post->PostNr);
	printf("Post Sted.: %s\n",post->PostSted);
	printf("Telefon Nr: %s\n",post->Telefon);
}

/************************************************************************/
/* denne rutine finner den posten vi leter etter */

static struct Liste *finn_post(lhd)
struct Liste *lhd;
{
	register struct Liste *cr,*scr;
	register char soknavn[80];
	register int i;
	register char svar;

	printf("\x1b[2;0HFinn en person\n");
	printf("\nNavn (max 30 tegn) :");
	gets(soknavn);
	soknavn[29] = 0;
	
	printf("\x1b[2;20HSøker... ");

	scr = cr = lhd;

	while (cr){
		if ((i = mystrcmp(cr->Navn,soknavn)) < 0){
			scr = cr;
			cr = cr->neste;
		}
		else
			break;
	}

	if (i == 0) {
		printf("Navn funnet!\n");
	}
	else {
		printf("Ikke funnet! Nærmeste navn\n");
	}

	while (cr) {
		vis_post(cr);
		printf("\n Gå til neste navn (n = neste)? ");

		if ((svar = toupper(getchar())) != '\n')
			getchar();

		if(svar == 'N'){
			scr = cr;
			cr = cr->neste;
		}
		else
			break;
	}

	if (cr)
		return(cr);
	else
		return(scr);
}

/************************************************************************/
/* denne rutinen flytter en post ut av listen mens den redigeres */

static void plukk_ut_post(hode,slutt,sp)
register struct Liste **hode,**slutt;
register struct Liste *sp;
{
	if (sp == *hode) {		/* posten er lik hode */
		if ((*hode)->neste) {	/* hvis det er flere poster */
			*hode = sp->neste;	/* sett listehode til neste post */
			(*hode)->forrige = NULL;	/* oppdater forrige peker i nytt listehode */
		}
		else { /* ingen flere poster */
			*hode = NULL;		/* listhode settes til NULL */
			*slutt = NULL;		/* listeslutt settes også til NULL */
		}
	}
	else if (sp == *slutt) {	/* posten er lik listeslutt */
		*slutt = sp->forrige;	/* listeslutt settes til forrige post */
		(*slutt)->neste = NULL;	/* ny listeslutts neste peker oppdateres */
	}
	else {	/* posten er inne i listen */
		sp->forrige->neste = sp->neste;	/* oppdater peker til neste til forrige post */
		sp->neste->forrige = sp->forrige;	/* oppdater peker til forrige i neste post */
	}

	sp->forrige = NULL;	/* Null ut peker til neste post */
	sp->neste = NULL;	/* Null ut peker til forrige post */
}

/************************************************************************/
/* denne rutinen finner posten som skal endres */

static void Endre_post(hode,slutt)
struct Liste **hode,**slutt;
{
	register struct Liste *l;
	register char svar;
	char oldnavn[30];
	
	l = finn_post(*hode); /* finn den posten som skal forandres */
	if(l){
		vis_post(l); /* vi posten bruker vil forandre */
		strcpy(oldnavn,l->Navn); /* husk det gammle navnet */
		printf("\n Vil du endre denne posten (j/n)? ");

/* sjekk om bruker virkelig vil endre denne posten */

		while (1) {
			if((svar = toupper(getchar())) != '\n')
				getchar();
			if (svar == 'J')
				break;
			else {
				printf("Post IKKE endret!");
				return;
			}
		}
/* les inn nye data i posten */

		legg_inn_data(l);	/* les inn nye data */
/*
  Sammenlign det gammle navnet med det nye.
  Hvis navnet er forandret skal posten justeres i listen.
*/
		if (strcmp(oldnavn,l->Navn)) {
			plukk_ut_post(hode,slutt,l);	/* plukk ut posten og */
			sett_inn_post(hode,slutt,l);		/* sett den inn på nytt */
		}
	}
}

/************************************************************************/
/* denne rutinen fjerner en post fra listen og frigjør minnet til posten */

static void fjern_post(hode,slutt)
register struct Liste **hode,**slutt;
{
	register struct Liste *dn;
	char svar;

	dn = finn_post(*hode); /* finn posten som skal fjernes */

	if (!dn)
		return;

	vis_post(dn); /* vi posten som skal fjernes */
	printf("\nEr du sikker på at du vil fjerne denne (j/n)? ");

/* sjekk om bruker virkelig vil fjerne posten */

	while (1) {
		if((svar = toupper(getchar())) != '\n')
			getchar();
		if (svar == 'J')
			break;
		else {
			printf("Post IKKE fjernet!");
			return;
		}
	}
	printf("Post fjernes!");

/* her fjerner vi posten */

	if (dn == *hode) { /* hvis dette er den første post i listen */
		if (dn->neste) { /* sjekk om det er flere poster i listen */
			*hode = dn->neste;  	/* juster listehode til å peke på neste */
			(*hode)->forrige = NULL;/* sett forrige peker i listehode = NULL */
		}
		else
			*hode = NULL; /* Null ut listen, ingen flere poster i listen *7

		FreeMem(dn,LLENGDE); /* frigjør minnet til posten */
		return;
	}
	else if (dn == *slutt) { 	/* hvis dette er den siste posten i listen */
		*slutt = dn->forrige; 	/* listeslutt peker oppdateres til nest siste post*/
		(*slutt)->neste = NULL;	/* sett neste peker i listeslutt = NULL */
		FreeMem(dn,LLENGDE);	/* frigjør minnet til posten som er hektet av */
		return;
	}
	else {									/* Hold tunga rett i munnen når du prøver å forstå dette */
		dn->forrige->neste = dn->neste; 	/* peker til neste i forrige post settes til denne posts neste */
		dn->neste->forrige = dn->forrige;	/* peker til forrige i neste post settes til denne posts forrige */ 
		FreeMem(dn,LLENGDE);				/* frigjør minnet til posten som er tatt ut */
		return;
	}
}

/************************************************************************/
/* sett av minne til ny post, les inn data og sett posten inn i listen */

static void ny_post(hode,slutt)
struct Liste **hode,**slutt;
{
	register struct Liste *p;
	register int riktig,flere;
	char dummy;


	do {
		p = (struct Liste *)AllocMem(LLENGDE,MEMF_CLEAR);

		if (p) {
			riktig = FALSE;
			while (!riktig) {
				legg_inn_data(p);
				vis_post(p);
				printf("\nEr dette riktig (j/n)? ");

				while (1) {
					if((dummy = toupper(getchar())) != '\n')
						getchar();
					if(dummy == 'J' || dummy == 'N')
						break;
				}
				if (dummy == 'J')
					riktig = TRUE;
			}
			sett_inn_post(hode,slutt,p);
		}
		else
			printf("For Lite Minne for ny post!\n");

		printf("\nVil du legge inn flere ? ");
		flere = FALSE;

		while (1) {
			if((dummy = toupper(getchar())) != '\n')
				getchar();
			if(dummy == 'J' || dummy == 'N')
				break;
		}
		if (dummy == 'J')
			flere = TRUE;
		
	}while(flere);
}

/************************************************************************/

static int Vis_meny()
{
	register char v;
	register int dumm;

	printf("\f\n     H O V E D M E N Y\n\n");
	printf("  1 - Legg inn ny post\n");
	printf("  2 - Finn navn\n");
	printf("  3 - Endre post\n");
	printf("  4 - Slett post\n");
	printf("  5 - Vis alle navn\n");
	printf("  6 - Lagre liste\n");
	printf("  7 - Hent liste\n");
	printf("  0 - Avslutt\n");
	do {
		printf("\x1b[13;2H Valg :   \b\b");

		while ((v = getchar()) == '\n');
		getchar();

 		if (v > '7' || v < '0')
			printf("\nUgylding valg\n");

	} while (v > '7' || v < '0');

	dumm = (int)(v - '0');
	return(dumm);
}

/**************** her starter hovedprogrammet *****************/

void main()
{
	register struct Liste *denne;
	register int valg;

	do {
		valg = Vis_meny();
		printf("\f");
		switch (valg) {
			case 1: /* legg inn nytt navn */
				ny_post(&lhode,&lslutt);
				break;

			case 2: /* finn navn */
				denne = finn_post(lhode);
				vis_post(denne);
				vent();
				break;
			
			case 3: /* endre post */
				Endre_post(&lhode,&lslutt);
				vent();
				break;

			case 4: /* slett navn */
				fjern_post(&lhode,&lslutt);
				vent();
				break;

			case 5: /* vis alle */
				vis_poster(lhode);
				vent();
				break;

			case 6: /* lagre navn */
				lagre_liste(lhode);
				vent();
				break;

			case 7: /* hent navn */
				hent_liste(&lhode,&lslutt);
				vent();
				break;

			case 0: /* avslutt */
				break;
		}
	} while (valg != 0);

	slett_alt(lhode);
}
