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

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

                              Programmert av 
                    Ørjan Eriksen og Torstein Pettersen

                          hentlagre.c   leksjon 5 
  
**************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <arp/arpbase.h>
#include <arp/arp_proto.h>
#include <proto/dos.h>
#include <dos.h>

#include "base.h"

/* externe variabler og funksjoner */

extern void sett_inn_post(struct Liste **,struct Liste **,struct Liste *);
extern void show_warn(char *);

extern struct IntuitionBase *IntuitionBase;
extern struct ArpBase *ArpBase;
extern struct GfxBase *GfxBase;
extern struct Window *w;

/* funksjoner tilgjengelig for andre moduler */

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

/* variabler og funksjoner kun for denne modulen */

static int finn_fil_navn(char *);

static struct FileRequester *frq; /* peker til kontroll struktur for arp filrequester */
static BPTR dirlock = NULL; /* lock til den katalogen vi står i */
static char filename[40] = {0,}; /* filnavn */
static char dirname[200] = {0,}; /* katalognavn */
static char virkeligfilnavn[256] = {0,}; /* sammenslåing av katalognavn og filnavn */
static long fd;

/* dette er makro som setter sammen fire byte til ett lonf word */
#define MakeID(a,b,c,d) ( (long)(a)<<24 | (long)(b)<<16 | (long)(c)<<8 | (d) )

/* sammensetting av D,B,H og D til et long word DBHD */
#define DBHD MakeID('D','B','H','D')

/* Image data til snorke pointeren */
static USHORT chip WaitSpriteData[] = {
	0x0000,0x0000,0x0000,0x0FE0,0x0740,0x18B0,0x0FE0,0x7018,
	0x3FF0,0xC008,0x7FF0,0x9E0C,0x7FF8,0x8406,0x7FFC,0x8802,
	0xFFFC,0x1E03,0x7FFE,0x80F1,0x7FFE,0x8021,0x3FFF,0x4040,
	0x7FFE,0x80F1,0x3FFE,0xC001,0x1FFC,0x6003,0x0FF8,0x3006,
	0x03F0,0x1C0C,0x00E0,0x0718,0x0780,0x0870,0x0FE0,0x1010,
	0x0740,0x0820,0x0000,0x0FE0,0x01C0,0x0220,0x03E0,0x0410,
	0x00C0,0x0330,0x0000,0x00E0,0x0000,0x0000
};

/**************************** funksjoner *****************************/

/*
  Denne rutinen finner navnet på katalogen vi står i og åpner 
  arp fil requestern i riktig katalog.
  filename, dirname og virkeligfilnavn blir også oppdatert.
*/

static int finn_fil_navn(tittel)
char *tittel;
{
	register int i;
/*
  Her finner vi vilken katalog vi står i og overfører navnet
  på hele "path'en" til dirname
*/

	if (dirlock == NULL) { /* bare hvis vi ikke har den allerede */
		dirlock = ((struct Process *)FindTask(NULL))->pr_CurrentDir; /* lock på katalog */

		if (getpath(dirlock,dirname) != NULL){ /* finn path navn */
			show_warn("Kunne ikke finne \"current dir\"");
		}
	}
/*
  Setter av minne til structuren som arp fil requestern trenger,
  og setter alle poster i strukturen til 0 (MEMF_CLEAR)
*/
	if (!(frq = (struct FileRequester *)
			AllocMem(sizeof(struct FileRequester),MEMF_CLEAR))) {
		show_warn("For lite minne for filrequester data!");
		return(0); /* returner avslutt */
	}

/* sett katalog navn, fil navn og navn på vinduet */
	frq->fr_Hail = tittel;
	frq->fr_File = filename;
	frq->fr_Dir = dirname;
	
/* åpne selve fil requesterne */
	if (!FileRequest(frq)) { /* hvis bruker velger "Cancel" avbryter vi alt */
		FreeMem(frq,sizeof(struct FileRequester)); 	/* frigjør minnet til filrequester data */
		show_warn("Fil requester avbrutt!");		/* vis hvorfor avbrudd */
		return(0); /* returner avslutt */
	}
	FreeMem(frq,sizeof(struct FileRequester)); 		/* frigjør minnet til filrequester data */

/* kopier dirname til virkeligfilnavn */

	strcpy(virkeligfilnavn,dirname);

/*
  finn ut om dirname er gitt og isåfall undersøk om der avsluttes
  med '/' eller ':', hvis ikke legges '/' til slik at virkelig
  filnavn blir riktig
*/
	i = strlen(dirname) - 1; /* posisjon til siste tegn i dirname */

	if (i > 0 && dirname[i] != ':' && dirname[i] != '/')
		strcat(virkeligfilnavn,"/"); 				/* legg til '/' */

	strcat(virkeligfilnavn,filename);				/* legg til filnavn */
	show_warn(virkeligfilnavn);						/* vis filnavn */
	return(1);										/* returner ok */
}

/************************************************************************/
/* denne rutinen lagrer hele listen på disk */

void lagre_liste(hode)
struct Liste *hode;
{
	register struct Liste *cr;

/* finn filename, dirname og virkeligfilnavn */

	if (!finn_fil_navn("Lagre fil")) 
		return;

/* sett pointer til snorke vente tegn */

	SetPointer(w,(short *)&WaitSpriteData,25,16,-4,-4);

/* prøv å åpne en ny fil, eller åpne en gammel med overskriving */

	if ((fd = Open(virkeligfilnavn,MODE_NEWFILE)) == NULL) {
		show_warn("Filen kunne ikke åpnes!");
		goto openerror;
	}

/* skriv fire bokstavers ID på filen */

	if (Write(fd,"DBHD",4) != 4)
		goto writeerror;

	cr = hode;

/* lagre hele poster uten de to pekerene i slutten av strukturen */

	while (cr) { /* fortsett til listen er tom */
		if (Write(fd,(char *)cr,LLENGDE-8) != LLENGDE-8) {
			show_warn("Feil under skriving!");
			goto writeerror;
		}

		cr = cr->neste;				/* neste post */
	}

	show_warn("Lagring ferdig!");

writeerror:
	Close(fd); /* lukk filen */

openerror:
	ClearPointer(w); /* set pointer tilbake til normal */
}

/************************************************************************/
/* hent liste fra disk */

struct Liste *hent_liste(hode,sist)
struct Liste **hode,**sist;
{
	register struct Liste *cr;
	register int i;
	ULONG buff;

/* åpne arp fil requester og få filnavn */
	if (!finn_fil_navn("Hent fil"))
		return(*hode);

/* sett pointer til snorke merke */

	SetPointer(w,(short *)WaitSpriteData,25,16,-4,-4);

/* åpne filen som eksisterer fra før */

	if ((fd = Open(virkeligfilnavn,MODE_OLDFILE)) == NULL) {
		show_warn("Filen kunne ikke åpnes!");
		goto openerror;
	}

/* les de fire første tegnene i filen */

	if (Read(fd,(char *)&buff,4) != 4) {
		show_warn("Feil under lesing av filen");
		goto readerror;
	}

/* sjekk om tegnene var DBHD */

	if (buff != DBHD) {
		show_warn("Feil filtype, dette er ikke en DBHD fil!");
		goto readerror;
	}

/* sett av minne til en post */

	cr = (struct Liste *)AllocMem(LLENGDE,MEMF_CLEAR);

	if (cr) {
		FOREVER	{ /* FOREVER er definert som "for(;;)" */

/* les hele filen, og sett av minne etterhvert som vi leser */

			if ((Read(fd,(char *)cr,LLENGDE-8) == LLENGDE-8)  && (cr != NULL)) {
				sett_inn_post(hode,sist,cr);
				cr = (struct Liste *)AllocMem(LLENGDE,MEMF_CLEAR);
			}
/*
  Avbryt når vi får lesefeil eller når vi når slutten.
  Vi har satt av minne til en post for mye,
  defor må vi frigjøre det før vi forsetter
*/
			else {
				FreeMem(cr,LLENGDE);
				break; /* avbryt FOREVER loopen */
			}
		}
	}

	show_warn("Innlesning Ferdig!");

readerror:
	Close(fd);

openerror:
/* sett pointer tilbake til normal */
	ClearPointer(w);
	return(*hode); /* returnere peker til listehode */
}
