#include "filereq.h"

main(argc,argv)
int argc;
char *argv[];
{
	char *name;
	name=(char *) get_file("File requester",150,30);
	if (name!=NULL) printf("%s\n",name);
	exit(0);
}

get_file(title,wx,wy)
char *title;
int wx,wy;
{
	struct FileLock *lock;
	struct FileInfoBlock *finfo;
	int gadgetid, x, y, selfile=-1;
	struct Gadget *gad;
	char np[256],op[256];
	BOOL fail=FALSE;

	finfo=(struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),MEMF_CHIP|MEMF_CLEAR);
	IntuitionBase=(struct IntuitionBase *) OpenLibrary("intuition.library",0);
	GfxBase=(struct GfxBase *) OpenLibrary("graphics.library",0);
	DosBase=(struct DosBase *) OpenLibrary("dos.library",0);
	rootnode=(struct RootNode *) DosBase->dl_Root;
	dosinfo=(struct DosInfo *) BADDR(rootnode->rn_Info);
	filewin.Screen=IntuitionBase->ActiveScreen;
	if (wx>374) wx=374; if (wy>48) wy=48;
	filewin.LeftEdge=wx; filewin.TopEdge=wy;
	Window=(struct Window *) OpenWindow(&filewin);
	SetWindowTitles(Window,title,0);
	redir:
	if (pathdobuffer[(strlen(pathdobuffer)-1)]!='/' &&
		pathdobuffer[(strlen(pathdobuffer)-1)]!=':' &&
		strlen(pathdobuffer)>0)
		strcat(pathdobuffer,"/");
	for (x=0;x<10;x++) {
		sprintf(FileGadgetText[x].IText,"                              ");
		RefreshGList(&FileGadget[x],Window,NULL,1);
	}
	RefreshGList(&PathGadget,Window,NULL,1);
	if ((lock=Lock(pathdobuffer,ACCESS_READ))==0) {
		sprintf(pathdobuffer,"");
			lock=Lock(pathdobuffer,ACCESS_READ);
		RefreshGList(&PathGadget,Window,NULL,1);
	}
	UDInfo.VertPot=0; UDInfo.VertBody=0xffff;
	RefreshGList(&UDGadget,Window,NULL,1);
	PathInfo.BufferPos=strlen(pathdobuffer);
	ActivateGadget(&FileSGadget,Window,NULL);
	strcpy(op,pathdobuffer);
	Examine(lock,finfo);
	filecount=0; offset=0; oldoffset=-1; selfile=-1; deviceslisted=FALSE;
	while ((ExNext(lock,finfo))!=0) {
		strcpy(files[filecount].fl_filename,finfo->fib_FileName);
		files[filecount].fl_filetype=finfo->fib_DirEntryType;
		++filecount;
		if (FMsg=GetMsg(Window->UserPort)) {
			ReplyMsg(FMsg);
			switch (FMsg->Class) {
				case CLOSEWINDOW:
					UnLock(lock);
					fail=TRUE;
					goto finished;
					break;
				case GADGETUP:
					gad=(struct Gadget *) FMsg->IAddress;
					gadgetid=gad->GadgetID;
					switch (gadgetid) {
						case PATH:
							if (strcmp(op,pathdobuffer)==0) break;
							UnLock(lock);
							if (pathdobuffer[(strlen(pathdobuffer)-1)]!='/' &&
								pathdobuffer[(strlen(pathdobuffer)-1)]!=':')
								strcat(pathdobuffer,"/");
							goto redir;
							break;
						case FILE:
							sprintf(filename,"%s%s",pathdobuffer,filedobuffer);
							UnLock(lock);
							goto finished;
							break;
						case PARENT:
							if (pathdobuffer[(strlen(pathdobuffer)-1)]!='/') break;
							for (x=strlen(pathdobuffer)-2;x>=0;x--) {
								if (pathdobuffer[x]=='/') {
									for (y=0;y<x;y++) np[y]=pathdobuffer[y];
									np[y++]='\0';
									break;
								}
								else if (pathdobuffer[x]==':') {
									for (y=0;y<=x;y++) np[y]=pathdobuffer[y];
									np[y++]='\0';
									break;
								}
							}
							sprintf(pathdobuffer,"%s",np);
							goto redir;
						case CANCEL:
							fail=TRUE;
							goto finished;
							break;
						case OKAY:
							sprintf(filename,"%s%s",pathdobuffer,filedobuffer);
							goto finished;
							break;
						default:
							break;
					}
					break;
				default:
					break;
			}
		}
	}
	UnLock(lock);
	Sort();
	DisplayFiles();
	vertpot=0;
	if (filecount<10) UDInfo.VertBody=0xffff;
	else if (filecount<20) UDInfo.VertBody=0x7fff;
	else UDInfo.VertBody=0xffff/(filecount/10);
	RefreshGList(&UDGadget,Window,NULL,1);
	FOREVER {
		Wait(1<<Window->UserPort->mp_SigBit);
		while (FMsg=GetMsg(Window->UserPort)) {
			ReplyMsg(FMsg);
			switch (FMsg->Class) {
				case CLOSEWINDOW:
					fail=TRUE;
					goto finished;
					break;

				case MOUSEBUTTONS:
					if (FMsg->Code!=MENUDOWN) break;
					if (deviceslisted) break;
					deviceslisted=TRUE;
					Forbid();
					devlist=(struct DeviceList *) BADDR(dosinfo->di_DevInfo);
					while (devlist) {
						if (devlist->dl_Type!=NULL) {
							devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
							continue;
						}
						if (devlist->dl_Task) {
							conbstr((BPTR) devlist->dl_Name,files[filecount].fl_filename);
							strcat(files[filecount].fl_filename,":");
							files[filecount].fl_filetype=0;
							++filecount;
						}
						devlist=(struct DeviceList *) BADDR(devlist->dl_Next);
					}
					Permit();
					offset=0; oldoffset=-1; selfile=-1;
					DisplayFiles();
					vertpot=0;
					if (filecount<10) UDInfo.VertBody=0xffff;
					else if (filecount<20) UDInfo.VertBody=0x7fff;
					else UDInfo.VertBody=0xffff/(filecount/10);
					RefreshGList(&UDGadget,Window,NULL,1);
					ActivateGadget(&PathGadget,Window,NULL);
					break;

				case GADGETUP:
					gad=(struct Gadget *) FMsg->IAddress;
					gadgetid=gad->GadgetID;
					if (gadgetid<10) {
						if (offset+gadgetid>=filecount) break;
						if (files[offset+gadgetid].fl_filetype>0) {
							if (pathdobuffer[(strlen(pathdobuffer)-1)]!='/' &&
								pathdobuffer[(strlen(pathdobuffer)-1)]!=':' &&
								strlen(pathdobuffer)>0)
								strcat(pathdobuffer,"/");
								strcat(pathdobuffer,files[offset+gadgetid].fl_filename);
								strcat(pathdobuffer,"/");
								goto redir;
							}
						else if (files[offset+gadgetid].fl_filetype==0) {
							sprintf(pathdobuffer,"%s",files[offset+gadgetid].fl_filename);
							goto redir;
						}
						else {
							if (selfile==offset+gadgetid) {
								sprintf(filename,"%s%s",pathdobuffer,filedobuffer);
								goto finished;
							}
							strcpy(filedobuffer,files[offset+gadgetid].fl_filename);
							RefreshGList(&FileSGadget,Window,NULL,1);
							selfile=offset+gadgetid;
						}				
					}
					switch (gadgetid) {
						case PARENT:
							if (pathdobuffer[(strlen(pathdobuffer)-1)]!='/') break;
							for (x=strlen(pathdobuffer)-2;x>=0;x--) {
								if (pathdobuffer[x]=='/') {
									for (y=0;y<x;y++) np[y]=pathdobuffer[y];
									np[y++]='\0';
									break;
								}
								else if (pathdobuffer[x]==':') {
									for (y=0;y<=x;y++) np[y]=pathdobuffer[y];
									np[y++]='\0';
									break;
								}
							}
							sprintf(pathdobuffer,"%s",np);
							goto redir;
							
						case PATH:
							if (strcmp(op,pathdobuffer)==0) break;
							goto redir;
							break;

						case FILE:
							sprintf(filename,"%s%s",pathdobuffer,filedobuffer);
							goto finished;
							break;
							
						case CANCEL:
							fail=TRUE;
							goto finished;
							break;

						case OKAY:
							sprintf(filename,"%s%s",pathdobuffer,filedobuffer);
							goto finished;
							break;

						case UPDOWN:
							offset=(10*UDInfo.VertPot)/UDInfo.VertBody;
							if (offset>(filecount-10)) offset=filecount-10;
							if (offset<0) offset=0;
							DisplayFiles();
							if (((10*UDInfo.VertPot)/UDInfo.VertBody)>(filecount-10)) {
								UDInfo.VertPot=(UDInfo.VertBody*(filecount-10))/10;
								RefreshGList(&UDGadget,Window,NULL,1);
							}
							break;

						default:
							break;
					}
					break;

				case GADGETDOWN:
					gad=(struct Gadget *) FMsg->IAddress;
					gadgetid=gad->GadgetID;
					switch (gadgetid) {
						case UPDOWN:
							if (!(UDInfo.Flags&KNOBHIT)) break;
							while (MouseButton()) {
								if (offset==((10*UDInfo.VertPot)/UDInfo.VertBody)) continue;
								if (((10*UDInfo.VertPot)/UDInfo.VertBody)>((UDInfo.VertBody*filecount)/10))
									continue;
								offset=(10*UDInfo.VertPot)/UDInfo.VertBody;
								if (offset>(filecount-10)) offset=filecount-10;
								if (offset<0) offset=0;
								DisplayFiles();
							}
							if (((10*UDInfo.VertPot)/UDInfo.VertBody)>(filecount-10)) {
								UDInfo.VertPot=(UDInfo.VertBody*(filecount-10))/10;
								RefreshGList(&UDGadget,Window,NULL,1);
							}
							break;
						case MOVEUP:
							x=0;
							--offset; if (offset<0) offset=0;
							if ((DisplayFiles())!=0)
								UpDateProp();
							while (MouseButton()) {
								x++;
								if (x>250) {
									--offset; if (offset<0) offset=0;
									if ((DisplayFiles())!=0)
										UpDateProp();
									x=0;
								}
							}
							break;
						case MOVEDOWN:
							x=0;
							++offset; if (offset>(filecount-10)) offset=filecount-10;
							if (offset<0) offset=0;
							if ((DisplayFiles())!=0)
								UpDateProp();
							while (MouseButton()) {
								x++;
								if (x>250) {
									++offset; if (offset>(filecount-10)) offset=filecount-10;
									if (offset<0) offset=0;
									if ((DisplayFiles())!=0)
										UpDateProp();
									x=0;
								}
							}
							break;

						default:
							break;
					}
					break;

				default:
					break;
			}
		}
	}
	finished:
	FreeMem(finfo,sizeof(struct FileInfoBlock));
	CloseWindow(Window);
	CloseLibrary(IntuitionBase);
	CloseLibrary(GfxBase);
	CloseLibrary(DosBase);
	if (fail || strlen(filedobuffer)==0) return(NULL);
	return(filename);
}

DisplayFiles()
{
	int a=0,dy,s;
	if (offset==oldoffset) return(0);
	if (offset>filecount) offset=filecount-10;
	dy=(oldoffset-offset)*9;
	if (oldoffset=-1) dy=0;
	if (dy>100) dy=100;
	if (dy<-100) dy=-100;
	ScrollRaster(Window->RPort,0,dy,5,25,242,125);
	if (dy<0) dy=-dy; dy/=10;
	if (oldoffset-offset<0) a=10-dy; else a=0;
	if (oldoffset=-1) { a=0; dy=10; }
	while (a+offset<filecount) {
		if (a==dy) break;
		if (files[offset+a].fl_filetype>0) FileGadgetText[a].FrontPen=3;
		else if (files[offset+a].fl_filetype==0) FileGadgetText[a].FrontPen=2;
		else FileGadgetText[a].FrontPen=1;
		strcpy(FileGadgetText[a].IText,files[offset+a].fl_filename);
		for (s=strlen(files[offset+a].fl_filename);s<30;s++)
			strcat(FileGadgetText[a].IText," ");
		RefreshGList(&FileGadget[a],Window,NULL,1);
		++a;
	}
	oldoffset=offset;
	return(1);
}

UpDateProp()
{
	vertpot=(UDInfo.VertBody*offset)/10;
	UDInfo.VertPot=vertpot;
	RefreshGList(&UDGadget,Window,NULL,1);
}

MouseButton()
{
	return(!((USHORT)ciaa.ciapra>>6&1));
}

Sort()
{
	int gap,i,j;
	char temp[31];
	int itemp;

	for (gap=filecount/2;gap>0;gap/=2)
		for (i=gap;i<filecount;i++)
			for (j=i-gap;j>=0;j-=gap) {
				if (mystrcmp(files[j].fl_filename,files[j+gap].fl_filename)<=0) break;
				sprintf(temp,"%s",files[j].fl_filename);
				sprintf(files[j].fl_filename,"%s",files[j+gap].fl_filename);
				sprintf(files[j+gap].fl_filename,"%s",temp);
				itemp=files[j].fl_filetype;
				files[j].fl_filetype=files[j+gap].fl_filetype;
				files[j+gap].fl_filetype=itemp;
			}
}

mystrcmp(s,t)
char s[], t[];
{
	int i;
	i=0;
	while (toupper(s[i])==toupper(t[i]))
		if (s[i++]=='\0') return(0);
	return(toupper(s[i])-toupper(t[i]));
}

conbstr(in,out)
BSTR in;
char *out;
{
	register UBYTE *ch;
	register int len,i;
	ch=(UBYTE *) BADDR(in);
	len=(int) *(ch++);
	len=(len>20)?20:len;
	for (i=0;i<len;i++) out[i]=*(ch++);
	out[i]='\0';
}
