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

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

                              Programmert av 
                    Ørjan Eriksen og Torstein Pettersen

                          database.c   leksjon 3 
  
**************************************************************************/

#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 legginn_data(struct Liste *);
static struct Liste *finn_post(struct Liste *);
static void slett_alt(struct Liste *);
static void ny_post(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 å kunne sortere de norske tegnene æ, ø, og å  
  Denne rutinen sammenligner to tekst strenger og gir følgende resultat:
		str1 > str2  -> positivt
		str1 < str2  -> negativt
		str1 = str2  -> 0

  Nå lurer du kanskje på hvorfor vi ikke bruker strcmp som allerede
  finnes i kompilatoren.
  Grunnen er at standard strcmp ikke vil sortere de norske tegnenen
  Æ, Ø, Å riktig. strcmp bruker signed char, dvs.  verdier fra -128 til +127,
  dermed blir de Æ Ø Å negativ fordi de ligger over 127 i ASCII tabellen.
  Dette fører til at Alle navn som begyner med Æ, Ø eller Å kommer fremst
  i listen. Denne rutinen gjør hvert tegn i navnet om til short etterhvert
  som den sammenligner tegnene, dermed unngår vi det første problemet.
  Vi må også justere for bokstaven 'å', som ligger foran 'æ' og 'ø' i ASCII
  tabellen. 
*/

static int mystrcmp(str1,str2)
register UBYTE *str1,*str2;		/* Vi lurer kompilatoren til å tro at    */
{								/* tekstenen som kommer er av typen      */
								/* unsigned byte. Dvs at ASCII verdiene  */
								/* til tegnene er mellom 0 og 255        */

	register short s1,s2;
	register UBYTE c1,c2;
	
	while (*str1) {
/*
  Her gjør vi om et tegn i str1 og et tegn i str2 til short,
  uten at kompilatoren utfører fortegnsjustering
  Eksempel:
     UBYTE 'Ø' til short = 175 ---> uten fortegnsjustering 
     char 'Ø' til short = -81  ---> med fortegnsjustering
*/
		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 */
/*
  Uheldigvis ligger 'å' foran 'æ' og 'ø' i ASCII tabellen, derfor legger
  vi til 100 når ett eller begge tegnene er lik 'å', slik at 'å' kommer
  etter 'æ' og 'ø'.
*/
		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 tegnene er forskjellig */
		if (s1-s2)
			return(s1-s2); /* returner differansen hvis de er forskjellig */
		str1++; /* øk begge tekst pekere 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; 		/* peker til en peker til listehode */
struct Liste **lsl; 		/* peker til en peker til listeslutt */
register struct Liste *pst; /* peker til post som skal settes inn */
{
	register struct Liste *crt; /* peker til en post i listen */

	if (pst == NULL)
		return; /* hvis det ikke kommer en ny post inn avbryter vi */

/* crt settes til å peke på den første posten i listen */

	crt = *lhd;

	if (crt == NULL) { 	/* hvis listen er tom settes posten inn som den */
		*lhd = pst;		/* første i listen */
		*lsl = pst;		/* siste post er lik første post */
		return;
	}
	else {
/*
  Hvis det er poster i listen søker vi fra begynelsen av listen til vi
  finner en post som har et navn som er etter det navnet vi skal putte
  inn i listen.
*/
		while (crt){
			if (mystrcmp(crt->Navn,pst->Navn) < 0) /* mystrcmp er forklart nedenfor */
				crt = crt->neste; /* hopp til neste post i listen */
			else
				break; /* hvis denne posten er etter i alfabetet stopp her */
		}
		if (crt == *lhd) { 		/* hvis den nye posten skal være først i listen */
			crt->forrige = pst;	/* sett peker til listehode til den nye posten */
			pst->neste = crt;	/* sett neste peker i den nye posten til gammelt listehode */
			*lhd = pst;			/* sett listehode til å peke på den nye posten */
		}
		else if (crt) { /* hvis posten skal settes inn inne i listen */
			pst->neste = crt; 			/* ny posts neste peker settes til funnet post */
			pst->forrige = crt->forrige;/* ny posts forrige peker settes til funnet posts forrige peker */
			crt->forrige->neste = pst;	/* neste pekeren til posten som kommer før funnet post settes til den nye posten */
			crt->forrige = pst;			/* sett forrige peker i funnet post til ny post */
		}
		else if (crt == NULL) { /* hvis posten skal settes inn i slutten av listen */
			pst->forrige = *lsl; 		/* sett ny posts forrige peker til gammel listeslutt */
			pst->forrige->neste = pst;	/* sett neste peker i sistepost til ny post */
			*lsl = pst;					/* sett listehode til å peke på ny post */
		}
	}
}

/****************** 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 legginn_data(pst)
struct Liste *pst;
{
 	char dummy[80];

	printf("\f\x1b[3;0H\x1b[JSkriv Inn data for en person \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 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 char svar;
	register int i;

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

/*
  Hvis vi ikke fant posten i listen gjør vi det mulig
  å gå videre til neste post, dette kan vi gjøre fordi listen 
  holdes sortert hele tiden.
*/
	if (i == 0) {
		printf("Navn funnet!\n");
	}
	else {
		printf("Ikke funnet! Nærmeste navn\n");
	}
/*
   denne løkken avbrytes når vi når siste post i listen eller 
   hvis bruker velger å bruke en post
*/
	while (cr) {
		vis_post(cr); /* vis posten som er funnet */
		printf("\n Gå til neste navn (n = neste)? ");

		if ((svar = toupper(getchar())) != '\n')
			getchar(); /* denne er bare for å fjerne \n fra input bufferen */

		if(svar == 'N'){
			scr = cr; 			/* lagre nest siste post */
			cr = cr->neste; 	/* gå til neste post */
		}
		else
			break; 				/* bruk denne posten */
	}
		
	if (cr) 			/* hvis CR er en post returneres denne */
		return(cr);
	else 				/* hvis ikke returneres den forrige posten */
		return(scr);
}

/*********************************************************************/
/* Sett av minne til en ny post, les inn data og sett posten inn i listen 
   Rutinen er blitt litt kortere fordi innsetting av ny post er flyttet
   ut som en egen rutine. */

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) {
				legginn_data(p);
				vis_post(p);
				printf("\nEr dette riktig ? ");

				while (1) {
					if((dummy = toupper(getchar())) != '\n')
						getchar();
					if(dummy == 'J' || dummy == 'N')
						break;
				}
				if (dummy == 'J')
					riktig = TRUE;
			}
 /* sett inn posten i alfabetisk rekkefølge i listen */

			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 nytt navn\n");
	printf("  2 - Finn navn\n");
	printf("  3 - Lagre navn\n");
	printf("  4 - Hent navn\n");
	printf("  0 - Avslutt\n");
	do {
		printf("\x1b[12;2H Valg :   \b\b");

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

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

	} while (v > '4' || 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: /* lagre navn */
				lagre_liste(lhode);
				vent();
				break;

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

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

	slett_alt(lhode);
}
