/* MED - music editor by Teijo Kinnunen 1989, 1990 */
/* med-filereq.c -- the filerequester... */

#define FirstMember(list,memb) { list = memb; memb->next=memb->prev=0L; }
extern struct PropInfo propinfo[];
extern struct Window *window;
extern struct Gadget far gadget2[];
extern char kappaleennimi[];
extern struct RastPort *wrp;
extern struct Screen *screen;
extern struct StringInfo strinfo[];
extern UWORD chip mouse0[],chip mouse1[],nykyinenosio;
struct FData { struct FData *prev,*next; char fname[108]; LONG type; };
static struct FData *firstfd = NULL,*FindFData(),*filelist = NULL;
static WORD firstdspnum = -1,numfd = 0;
BPTR currdir = NULL;	/* lock of the current requester directory */
static UWORD propstep = 0;
static void ReadFNames(),ChangeCurrDir(),GetPath(),InsFData();
void FReqHandler(),InitFileReq(),FreeFDatas(),UpdateFReqDsp();

void UpdateFReqDsp()
{
	register WORD dspcnt,chrcnt;
	register struct FData *scanptr = firstfd;
	if(!currdir) {
		register UCOUNT linecnt;
		SetAPen(wrp,1);
		SetBPen(wrp,3);
		for(linecnt = 0; linecnt < 5; linecnt++) {
			Move(wrp,8,27 + linecnt * 8);
			if(linecnt == 2) Text(wrp," Choose drive  ",15);
			else Text(wrp,"               ",15);
		}
		return;
	}
	if(firstdspnum == -1 || firstfd == 0) return;
	for(dspcnt = 0; dspcnt < firstdspnum; dspcnt++)
		if(!(scanptr = scanptr->next)) {
			firstdspnum = dspcnt - 4;
			if(firstdspnum < 0) firstdspnum = 0;
			UpdateFReqDsp();
			return;
		}
	for(dspcnt = 0; dspcnt < 5; dspcnt++) {
		char dspbuf[15];
		Move(wrp,8,27 + 8 * dspcnt);
		memcpy(dspbuf,"               ",15);
		if(scanptr) {
			if(scanptr->type > 0) SetAPen(wrp,1);
			else SetAPen(wrp,0);
			for(chrcnt = 0; chrcnt < 15; chrcnt++) {
				if(scanptr->fname[chrcnt] == '\0') break;
				dspbuf[chrcnt] = scanptr->fname[chrcnt];
			}
			scanptr = scanptr->next;
		}
		Text(wrp,dspbuf,15);
	}
	SetAPen(wrp,0);
}

static void ReadFNames()
{
	register BPTR pdirtest;
	register struct FData *newptr = 0L;
	register struct FileInfoBlock *fib;
	register UWORD pos;
	FreeFDatas();
	if(!(fib = (struct FileInfoBlock *)AllocMem(sizeof(struct
		FileInfoBlock),MEMF_PUBLIC))) return;
	if(Examine(currdir,fib)) {
		pdirtest = ParentDir(currdir);
		if(pdirtest) {
			UnLock(pdirtest);
			newptr = (struct FData *)AllocMem(sizeof(struct
				FData),MEMF_PUBLIC);
			if(newptr) {
				strcpy(newptr->fname,"/ Parent Dir");
				InsFData(newptr,1);
			}
		}
		if(!pdirtest || (pdirtest && newptr)) { /* OK!! */
			for(;;) {
				if(!ExNext(currdir,fib)) break;
/* This very difficult "if" */	if(strlen(fib->fib_FileName) >= 5 &&
/* checks if the filename has */	!strcmp(&(fib->fib_FileName[
/* ".info"-suffix. */			strlen(fib->fib_FileName) - 5]),
					".info")) continue;
				newptr = (struct FData *)AllocMem(sizeof(struct
					FData),MEMF_PUBLIC);
				if(!newptr) break;
				strcpy(newptr->fname,fib->fib_FileName);
				InsFData(newptr,fib->fib_DirEntryType);
			}
		}
	}
	firstdspnum = 0;
	if(filelist) {
		if(firstfd) {
			for(newptr = firstfd; newptr->next; newptr =
				newptr->next);
			newptr->next = filelist;
			filelist->prev = newptr;
		}
		else firstfd = filelist;
	}
	UpdateFReqDsp();
	pos = RemoveGadget(window,&gadget2[6]);
	propinfo[0].VertPot = 0;
	AddGadget(window,&gadget2[6],pos);
	RefreshGList(&gadget2[6],window,NULL,1);
	FreeMem((void *)fib,sizeof(struct FileInfoBlock));
}

static void InsToList(struct FData **list,struct FData *fd)
{
	register struct FData *scanptr = *list;
	for(;stricmp(scanptr->fname,fd->fname) <= 0 && scanptr->next;
		scanptr = scanptr->next);
	if(!scanptr->next && stricmp(scanptr->fname,fd->fname) < 0) {
			fd->next = NULL;
			scanptr->next = fd;
			fd->prev = scanptr;
			return;
	}
	fd->next = scanptr;
	fd->prev = scanptr->prev;
	if(fd->prev) fd->prev->next = fd;
	else *list = fd;
	scanptr->prev = fd;
}

static void InsFData(struct FData *fdata,LONG type)
{
	fdata->type = type;
	if(type < 0) {
		if(filelist)	InsToList(&filelist,fdata);
		else FirstMember(filelist,fdata);
	}
	else {
		if(firstfd)	InsToList(&firstfd,fdata);
		else FirstMember(firstfd,fdata);
	}
	numfd++;
}

void FreeFDatas()
{
	register struct FData *freeptr = firstfd,*fptr2;
	while(freeptr) {
		fptr2 = freeptr->next;
		FreeMem((void *)freeptr,sizeof(struct FData));
		freeptr = fptr2;
	}
	firstfd = filelist = NULL;
	numfd = 0;
}

static void CalcNewPropSize()
{
	register UWORD pos;
	if(nykyinenosio == 2) pos = RemoveGadget(window,&gadget2[6]);
	propinfo[0].VertPot = 0;
	if(numfd <= 5)	{
		propinfo[0].VertBody = MAXBODY;
		propstep = 0;
	}
	else	{
		propinfo[0].VertBody = (MAXBODY * 5) / numfd;
		propstep = MAXBODY / (numfd - 5) - 1;
	}
	if(nykyinenosio != 2) return;
	AddGadget(window,&gadget2[6],pos);
	RefreshGList(&gadget2[6],window,NULL,1);
}
	
static void ChangeCurrDir(char *name)
{
	register BPTR newlock,oldcurr;
	register UWORD pos;
	struct FileInfoBlock *fib = AllocMem(sizeof(struct FileInfoBlock),
		MEMF_PUBLIC|MEMF_CLEAR);
	extern char hakemisto[];
	if(!fib) { Ilmoita("No memory for that!!"); return; }
	if(!strcmp(name,"/ Parent Dir")) newlock = ParentDir(currdir);
	else {
		if(currdir) oldcurr = CurrentDir(currdir);
		newlock = Lock(name,ACCESS_READ);
		if(currdir) CurrentDir(oldcurr);
		if(!newlock) {
			DisplayBeep(screen);
			FreeMem((void *)fib,sizeof(struct FileInfoBlock));
			return;
		}
	}
	if(!Examine(newlock,fib) || fib->fib_DirEntryType < 0) {
		UnLock(newlock);
		FreeMem((void *)fib,sizeof(struct FileInfoBlock));
		DisplayBeep(screen);
		return;
	}
	FreeMem((void *)fib,sizeof(struct FileInfoBlock));
	UnLock(currdir);
	currdir = newlock;
	SetPointer(window,&mouse0[0],23,16,-1,0);
	if(nykyinenosio == 2) pos = RemoveGadget(window,&gadget2[8]);
	GetPath(DupLock(newlock),hakemisto);
	strinfo[0].DispPos = strinfo[0].BufferPos = 0;
	if(nykyinenosio == 2) {
		AddGadget(window,&gadget2[8],pos);
		RefreshGList(&gadget2[8],window,NULL,1);
	}
	Ilmoita("Loading directory...");
	ReadFNames();
	Ilmoita(NULL);
	CalcNewPropSize();
	SetPointer(window,&mouse1[0],23,16,-1,0);
}

static void GetPath(BPTR lock,char *buff)
{
	register struct FileInfoBlock *fib;
	register BPTR pdirlock;
	*buff = '\0';
	if(!(fib = (struct FileInfoBlock *)AllocMem(sizeof(struct
		FileInfoBlock),MEMF_PUBLIC))) return;
	for(;;) {
		if(!Examine(lock,fib)) break;
		pdirlock = ParentDir(lock);
		strcat(fib->fib_FileName,pdirlock ? "/" : ":");
		if(strlen(buff) + strlen(fib->fib_FileName) < 99)
			strins(buff,fib->fib_FileName);
		if(!pdirlock) break;
		UnLock(lock);
		lock = pdirlock;
	}
	UnLock(lock);
	FreeMem((void *)fib,sizeof(struct FileInfoBlock));
	buff += strlen(buff) - 1;
	if(*buff == '/') *buff = '\0';
}

static struct FData *FindFData(num)
WORD num;
{
	register struct FData *scanptr = firstfd;
	if(num >= numfd) return(NULL);
	for(;num > 0 ;num--) scanptr = scanptr->next;
	return(scanptr);
}

void FReqHandler(UWORD gid)
{
	static char *drives[] = { "DF0:","DF1:","DF2:","DF3:","DH0:" };
	register UWORD pos;
	if(gid >= 0x20F && gid <= 0x213) ChangeCurrDir(drives[gid-0x20F]);
	else if(gid >= 0x200 && gid <= 0x204) {
		struct FData *tmpptr = FindFData(firstdspnum+(gid-0x200));
		if(tmpptr) {
			if(tmpptr->type > 0) ChangeCurrDir(tmpptr->fname);
			else {
				if(strlen(tmpptr->fname) < 49) {
					pos = RemoveGadget(window,&gadget2[9]);
					strcpy(kappaleennimi,tmpptr->fname);
					strinfo[1].DispPos = strinfo[1].BufferPos = 0;
					AddGadget(window,&gadget2[9],pos);
					RefreshGList(&gadget2[9],window,NULL,1);
				}
			}
		}
	}
	else if(gid == 0x205 && firstdspnum > 0) {
		pos = RemoveGadget(window,&gadget2[6]);
		if(propinfo[0].VertPot > propstep)
			propinfo[0].VertPot -= propstep;
		else	propinfo[0].VertPot = 0;
		AddGadget(window,&gadget2[6],pos);
		RefreshGList(&gadget2[6],window,NULL,1);
		gid = 0x206;
	}
	else if(gid == 0x207 && firstdspnum < numfd-5) {
		pos = RemoveGadget(window,&gadget2[6]);
		if(propinfo[0].VertPot < MAXPOT - propstep)
			propinfo[0].VertPot += propstep;
		else	propinfo[0].VertPot = MAXPOT;
		AddGadget(window,&gadget2[6],pos);
		RefreshGList(&gadget2[6],window,NULL,1);
		gid = 0x206;
	}
	else if(gid == 0x208) ChangeCurrDir(hakemisto);
	if(gid == 0x206) {
		if(propstep) firstdspnum = (propinfo[0].VertPot + propstep / 2) / propstep;
		else firstdspnum = 0;
		UpdateFReqDsp();
	}
}

void InsertSavedFile(char *name)
{
	struct FData *newentry,*lastdir;
	char *tstptr = name;
	while(*tstptr)  /* Does this file go to this directory ??? */
		if(*tstptr == ':' || *tstptr == '/') return; else tstptr++;
	if(!currdir) return;	/* The directory isn't displayed */
	newentry = (struct FData *)AllocMem(sizeof(struct
		FData),MEMF_PUBLIC|MEMF_CLEAR);
	if(!newentry) { Ilmoita("Memory..."); return; }
	strcpy(newentry->fname,name);
	InsFData(newentry,-1);
	if(!newentry->prev && firstfd) {
		for(lastdir = firstfd; lastdir->next; lastdir =
			lastdir->next);
		lastdir->next = newentry;
		newentry->prev = lastdir;
	}
	CalcNewPropSize();
	UpdateFReqDsp();
}

BPTR Open2(char *name,long mode)
{
	BPTR prevdir,openres;
	if(currdir) prevdir = CurrentDir(currdir);
	openres = Open(name,mode);
	if(currdir) CurrentDir(prevdir);
	return(openres);
}

BOOL IsHere(char *name)
{
	BPTR prevdir,lock;
	if(currdir) prevdir = CurrentDir(currdir);
	lock = Lock(name,ACCESS_READ);
	if(currdir) CurrentDir(prevdir);
	if(lock) { UnLock(lock); return(TRUE); }
	return(FALSE);
}
