#define INTUITIONPRIVATE 1
#include <devices/inputevent.h>
#include <devices/input.h>
#include <graphics/gfxbase.h>
#include <devices/console.h>
#include <libraries/reqbase.h>
#include <workbench/startup.h>
#include <functions.h>
#include <exec/exec.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>

#define HELP		1L<<mysignal
#define TASTE		((notepad != NULL) ? (1L<<inPort->mp_SigBit) : 0L)
#define WINDOW		((notepad != NULL) ? (1L<<notepad->UserPort->mp_SigBit) : 0L)
#define ENDE		SIGBREAKF_CTRL_C

#define SCREENYSIZE	256L
#define TEXTYSIZE	30L

void HandlerInterface();

struct MsgPort			*inPort = NULL, *outPort = NULL;
struct IOStdReq			*inReq = NULL, *npior = NULL, *npiow = NULL;
struct IntuitionBase	*IntuitionBase;
struct ReqBase			*ReqBase;
struct GfxBase			*GfxBase;
struct Window			*notepad = NULL;
struct FileRequester	MyFileReqStruct;
struct Process			*mytask = NULL;

APTR					olderrorwindow = NULL;
long					mysignal = 0L;
UBYTE					cb, text[TEXTYSIZE][80];		/* Notizblatt */
int						x, y;							/* Cursorposition */
char					filename[FCHARS+1],
						directoryname[DSIZE+1],
						answerarray[DSIZE+FCHARS+1];

struct Interrupt		HandlerData = { { NULL,NULL,0L,51L,NULL }, NULL, &HandlerInterface };


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


chrout(c)
  UBYTE c;
{
	npiow->io_Data = &c;
	npiow->io_Length = 1L;
	npiow->io_Command = CMD_WRITE;
	DoIO(npiow); GetMsg(outPort);
}

UBYTE chrin()
{	UBYTE c;

	npior->io_Data = &c;
	npior->io_Length = 1L;
	npior->io_Command = CMD_READ;
	DoIO(npior); GetMsg(inPort);
	return c;
}

myputs(s)
  char *s;
{
	npiow->io_Length = strlen(s);
	npiow->io_Data = s;
	npiow->io_Command = CMD_WRITE;
	DoIO(npiow); GetMsg(outPort);
}

clrTextspeicher()
{	register int i;

	for(i=0; i<TEXTYSIZE; i++)
	{	setmem(&text[i],79,32);
		text[i][79]=0;
	}
	text[TEXTYSIZE-1][78]=0;
}

OpenNotepad()
{	static struct NewWindow Newnotepad = {
		0,0,640,SCREENYSIZE,0,1,MOUSEBUTTONS+CLOSEWINDOW,
		ACTIVATE+NOCAREREFRESH+RMBTRAP+WINDOWDEPTH+WINDOWCLOSE+WINDOWDRAG,
		NULL,NULL,"Notizblatt",NULL,NULL,5,5,640,SCREENYSIZE,WBENCHSCREEN };
	register int i;
	struct Screen *s;

	s = IntuitionBase->ActiveScreen;
	if(s->Width >= 640 && s->Height >= SCREENYSIZE)
	{	Newnotepad.Type = CUSTOMSCREEN;
		Newnotepad.Screen = s;
	}
	else
	{	Newnotepad.Type = WBENCHSCREEN;
		Newnotepad.Screen = NULL;
		WBenchToFront();
	}

	if(notepad)
		WindowToFront(notepad);
	else
	{	if(notepad = OpenWindow(&Newnotepad))
		{	npiow->io_Data = notepad;
			OpenDevice("console.device", 0L, npiow, 0L);
			npior->io_Data = notepad;
			OpenDevice("console.device", 0L, npior, 0L);
			for(i=0; i<TEXTYSIZE; i++)
			{	myputs(&text[i]);
				if(i<TEXTYSIZE-1) chrout(10);
			}
			myputs("\233H");
			x = y = 0;
		}
	}
}

struct InputEvent *myHandler(event, data)
  struct InputEvent *event;
  APTR data;
{	register struct InputEvent *e, *oe = NULL, *ne = NULL;

	Forbid();
	for(e=event; e != NULL; e = ne)
	{
		ne = e->ie_NextEvent;
		if(e->ie_Class == IECLASS_RAWKEY)
		{
			if(e->ie_Code == 0x5F)		/* HELP-Taste ? */
			{
				Signal(mytask, 1L<<mysignal);

				if(oe) oe->ie_NextEvent = ne;
				else event = ne;
				e = NULL;
			}
		}
		if(e) oe = e;
	}

	Permit();
	return(event);
}

void HandlerInterface()
{
#asm
	movem.l	a4,-(sp)
	jsr		_geta4#
	movem.l	a0/a1,-(sp)
	jsr		_myHandler
	addq.l	#8,sp
	move.l	(sp)+,a4
#endasm
}

Init()
{
	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", NULL);
	GfxBase = IntuitionBase->GfxBase;

	if((ReqBase = OpenLibrary("req.library", NULL)) == NULL)
	{	DisplayBeep(0L);
		CloseLibrary(IntuitionBase);
		exit(20);
	}

	inPort = CreatePort("HelperIn", NULL);
	outPort = CreatePort("HelperOut", NULL);
	npior = CreateStdIO(inPort);	/* req für Console lesen */
	npiow = CreateStdIO(outPort);	/* req für Console schreiben */
	mysignal = AllocSignal(-1L);
	SetSignal(0L, 1L<<mysignal);
	mytask = FindTask(NULL);
	olderrorwindow = mytask->pr_WindowPtr;

	inReq = CreateStdIO(inPort);
	OpenDevice("input.device", 0L, inReq, 0L);
	inReq->io_Command = IND_ADDHANDLER;
	inReq->io_Data = (APTR)&HandlerData;
	DoIO(inReq);

	MyFileReqStruct.PathName = answerarray;
	MyFileReqStruct.Dir = directoryname;
	MyFileReqStruct.File = filename;
	MyFileReqStruct.dirnamescolor = 2;
	MyFileReqStruct.devicenamescolor = 2;
	clrTextspeicher();
}

Quit()
{
	FreeSignal(mysignal);
	inReq->io_Command = IND_REMHANDLER;
	inReq->io_Data = (APTR)&HandlerData;
	DoIO(inReq);
	CloseDevice(inReq);			/* input.device */

	if(notepad)
	{	AbortIO(npior);
		CloseDevice(npior);
		CloseDevice(npiow);
		CloseWindow(notepad);	/* notepad & console */
	}

	DeleteStdIO(inReq);
	DeleteStdIO(npior);
	DeleteStdIO(npiow);
	DeletePort(inPort);
	DeletePort(outPort);		/* io-strukturen */

	CloseLibrary(ReqBase);
	CloseLibrary(IntuitionBase);
	mytask->pr_WindowPtr = NULL;
	exit(0);
}

getzchn()		/* setzt nur den req auf... */
{
	npior->io_Data = &cb;			/* charbuffer */
	npior->io_Length = 1L;
	npior->io_Command = CMD_READ;
	SendIO(npior);
}

int UserRequest(text,a,b,c)
  char *text,*a,*b,*c;
{	static struct TRStructure meintrs =
	{ 0,0,0,0,0,0,"Dein Helper fragt dich:",0xFFFF,0,0,0,0,0,0 };

	meintrs.Text = text;
	meintrs.NegativeText = a;		/* 0 (rechts) */
	meintrs.PositiveText = b;		/* 1 (links) */
	meintrs.MiddleText = c;			/* 2 (mitte) */

	return TextRequest(&meintrs);
}

char *extend(name,ext)
  char *name, *ext;
{	static char buffer[40];
	char *s, *rindex();

	if(s = rindex(name, '.'))
		if(strncmp(s, ext) == 0) return name;

	strcpy(buffer,name);
	strcat(buffer,ext);
	return buffer;
}

HandleTaste()
{	char com[16];
	register char *s;
	FILE *fp;
	register int i;
	long uz;
	struct tm *tm;

	switch(cb)
	{	case 8:
			if(x!=0 || y!=0)
			{	chrout(8);
				if(--x < 0)
				{	x=78;
					if(--y < 0) y=0;
				}
			}
		case 127:
			myputs("\233P");
			strcpy(&text[y][x], &text[y][x+1]);
			break;
		case 13:
			if(++y < TEXTYSIZE)
				chrout(10);
			else
			{	y = TEXTYSIZE-1;
				chrout(13);
			}
			x = 0;
			break;
		case 12:
			chrout(12);
			clrTextspeicher();
			break;
		case 155:
			cb = chrin();
			switch(cb)
			{	case 'A':
					if(--y < 0)
						y = 0;
					else
						myputs("\233A");
					break;
				case 'B':
					if(++y > TEXTYSIZE-1)
						y = TEXTYSIZE-1;
					else
						myputs("\233B");
					break;
				case 'C':
					if(++x > 78)
					{	x = 0;
						if(++y > TEXTYSIZE-1)
						{	y=TEXTYSIZE-1;
							myputs("\233A");
						}
					}
					myputs("\233C");
					break;
				case 'D':
					if(--x < 0)
					{	x = 78;
						if(--y < 0)
						{	y=0;
							myputs("\233B");
						}
					}
					myputs("\233D");
					break;
				case 'T':
					y = 0;
					sprintf(com,"\233%d;%dH",y+1,x+1);
					myputs(com);
					break;
				case 'S':
					y = TEXTYSIZE-1;
					sprintf(com,"\233%d;%dH",y+1,x+1);
					myputs(com);
					break;
				case ' ':
					cb = chrin();
					if(cb == 'A')
					{	x = 0;
						sprintf(com,"\233%d;%dH",y+1,x+1);
						myputs(com);
					}
					else
					{	x = 78;
						sprintf(com,"\233%d;%dH",y+1,x+1);
						myputs(com);
					}
			}
			break;
		case 11:			/* K = Kill Zeile */
			myputs("\233M\233L");
			setmem(&text[y][0],79,32);
			text[y][79] = 0;
			break;
		case 5:				/* E = 1 Zchn Einfügen */
			myputs("\233@");
			movmem(&text[y][x],&text[y][x+1],78-x);
			text[y][x] = 32;
			break;
		case 19:			/* S = Speichern */
			MyFileReqStruct.Flags = FRQCACHINGM+FRQINFOGADGETM+FRQSAVINGM;
			MyFileReqStruct.Title = "Notizblatt abspeichern:";
			strcpy(directoryname, "T:");
			strcpy(MyFileReqStruct.Show, "*.note");
			if(FileRequester(&MyFileReqStruct))
			{	if(fp = fopen(s = extend(answerarray, ".note"), "w+"))
				{	fwrite(text, (int)(80*TEXTYSIZE), 1, fp);
					fclose(fp);
				}
				else SimpleRequest("Ich kann %s nicht öffnen.", s);
			}
			break;
		case 26:			/* Z = Zurückholen */
			MyFileReqStruct.Flags = FRQCACHINGM+FRQINFOGADGETM+FRQLOADINGM;
			MyFileReqStruct.Title = "Notizblatt zurückholen:";
			strcpy(directoryname, "T:");
			strcpy(MyFileReqStruct.Show, "*.note");
			if(FileRequester(&MyFileReqStruct))
			{	if(fp = fopen(s = extend(answerarray, ".note"), "r+"))
				{	fread(text, (int)(80*TEXTYSIZE), 1, fp);
					fclose(fp);
					myputs("\f");
					for(i=0; i<TEXTYSIZE; i++)
					{	myputs(&text[i]);
						if(i<TEXTYSIZE-1) chrout(10);
					}
					myputs("\233H");
					x = y = 0;
				}
				else SimpleRequest("Ich kann %s nicht öffnen.", s);
			}
			break;
		case 21:				/* U = Uhrzeit */
			if(x > 73) break;
			uz = time(0L);
			tm = gmtime(&uz);
			sprintf(com, "%02d:%02d", tm->tm_hour, tm->tm_min);
			myputs(com);
			movmem(com, &text[y][x], 5);
			x += 5;
			break;
		case 4:					/* D = Datum */
			if(x > 70) break;
			uz = time(0L);
			tm = gmtime(&uz);
			sprintf(com,"%02d.%02d.%02d", tm->tm_mday, tm->tm_mon+1, tm->tm_year);
			myputs(com);
			movmem(com, &text[y][x], 8);
			x += 8;
			break;
		default:
			if( ((cb>31)&&(cb<127)) || ((cb>160)&&(cb<255)) )
			{	if( (x==78) && (y==TEXTYSIZE-1) )
					chrout(7);
				else
				{
					chrout(cb);
					text[y][x] = cb;
					if(++x > 78)
					{	x=0;
						++y;
					}
				}
			}
	}
}

main(argc, argv)
  int argc;
  char *argv[];
{	register long signals;
	register int ix, iy, i;
	char more[32], com[16];
	BOOL wbtf = TRUE;
	struct IntuiMessage *m;
	ULONG class;

	Init();

	strcpy(more, "SYS:Utilities/More");
	for(i=1; i<argc; i++)
	{	if(argv[i][0] == '?')
		{	SimpleRequest("»Helper« Version 1.01d von Michael Balzer 1990\n"
						  "HotKey ist HELP (was sonst?), und vom CLI aus\n"
						  "gibt's folgende Optionen:\n"
						  "-mPRG{Anzeigeprg} -f0/1{WorkBenchToFront}\n"
						  "Defaultwerte: -mSYS:Utilities/More -f1");
			Quit();
		}
		else if(strncmp(argv[i], "-m", 2) == 0)
			strcpy(more, &argv[i][2]);
		else if(strncmp(argv[i], "-f", 2) == 0)
			wbtf = (argv[i][2] == '0') ? FALSE : TRUE;
	}

	do
	{	signals = Wait(HELP | TASTE | WINDOW | ENDE);
		mytask->pr_WindowPtr = IntuitionBase->ActiveScreen->FirstWindow;

		if(signals & HELP)
		{	switch(UserRequest("Was möchtest du?", " Text ansehen ", " Notizblatt ", " Farben ändern "))
			{	case 0:
					MyFileReqStruct.Flags = FRQCACHINGM+FRQINFOGADGETM+FRQLOADINGM;
					MyFileReqStruct.Title = "Bitte Text wählen:";
					strcpy(directoryname, "HELP:");
					MyFileReqStruct.Show[0] = 0;
					if(FileRequester(&MyFileReqStruct))
					{	if(wbtf) WBenchToFront();
						if(fexecl(more, more, answerarray, NULL) == -1)
							SimpleRequest("%s nicht ausführbar!", more);
						if(((struct Window *)mytask->pr_WindowPtr)->WScreen != IntuitionBase->FirstScreen)
							WBenchToBack();
					}
					break;
				case 1:
					OpenNotepad();
					getzchn();			/* Request für Tastendruck aufsetzen */
					break;
				case 2:
					ColorRequester(1L);
			}
		}

		if(signals & TASTE)
		{	GetMsg(inPort);		/* Reply entfernen */
			HandleTaste();
			cb=0;
			getzchn();
		}

		if(signals & WINDOW)
		{	if(m = (struct IntuiMessage *)GetMsg(notepad->UserPort))
			{	class = m->Class;
				ix = m->MouseX; iy = m->MouseY;
				ReplyMsg(m);
				if(class == CLOSEWINDOW)
				{	AbortIO(npior);
					CloseDevice(npior);
					CloseDevice(npiow);
					CloseWindow(notepad);
					notepad = NULL;
				}
				else if(class == MOUSEBUTTONS)
				{	x = (ix-4)/8;
					if(x>78) x=78;
					if(x<0) x=0;
					y = (iy-11)/8;
					if(y>TEXTYSIZE-1) y=TEXTYSIZE-1;
					if(y<0) y=0;
					sprintf(com,"\233%d;%dH",y+1,x+1);
					myputs(com);
				}
			}
		}
	} while(!(signals & ENDE));

	Quit();
}
