/* TextReader by Oren Peli, Copyright (c) 1987 BazboSOFT! */

#include <intuition/intuitionbase.h>	/* Added by Adams Douglas */
#include <devices/conunit.h>
#include <devices/input.h>
#include <exec/memory.h>
#include <graphics/gfxbase.h>
#include <libraries/dosextens.h>

extern void *AllocMem();

extern PLANEPTR AllocRaster();

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;

extern void *OpenLibrary();

extern void *CreateStdIO();

extern long findWindow();

struct ConUnit *conUnit = NULL;

struct Window *conWindow = NULL;

void *CreatePort() , *FindPort();

struct Process *FindTask();

struct IntuiMessage *GetMsg();

struct RastPort dummy_rastport , *trp = &dummy_rastport;
struct BitMap dummy_bitmap , *tbm = &dummy_bitmap;

struct RastPort dummy_rastport2 , *crp = &dummy_rastport2;
struct BitMap dummy_bitmap2 , *cbm = &dummy_bitmap2;


struct IntuiText ItemText = { 3 , 1 , JAM1 , 1 , 1 , NULL , (STRPTR) "Quit TextReader"
, NULL };

struct MenuItem MenuItem = { NULL , 0 , 0 , 121 , 10 , ITEMTEXT | ITEMENABLED |
HIGHCOMP, 0, (APTR) &ItemText , NULL , NULL , NULL , 0xFFFF };

struct Menu Menu = { NULL , 0 , 0 , 121 , 0 , MENUENABLED , " Quit" , &MenuItem };

struct chr_data
{
	char chr;
	char raw_data;
	char is_shifted;
	PLANEPTR pln;
};

struct chr_data chrs[] =
{
	{	' '	,	0x40	,	0	} ,
	{	'a'	,	0x20	,	0	} ,
	{	'b'	,	0x35	,	0	} ,
	{	'c'	,	0x33	,	0	} ,
	{	'd'	,	0x22	,	0	} ,
	{	'e'	,	0x12	,	0	} ,
	{	'f'	,	0x23	,	0	} ,
	{	'g'	,	0x24	,	0	} ,
	{	'h'	,	0x25	,	0	} ,
	{	'i'	,	0x17	,	0	} ,
	{	'j'	,	0x26	,	0	} ,
	{	'k'	,	0x27	,	0	} ,
	{	'l'	,	0x28	,	0	} ,
	{	'm'	,	0x37	,	0	} ,
	{	'n'	,	0x36	,	0	} ,
	{	'o'	,	0x18	,	0	} ,
	{	'p'	,	0x19	,	0	} ,
	{	'q'	,	0x10	,	0	} ,
	{	'r'	,	0x13	,	0	} ,
	{	's'	,	0x21	,	0	} ,
	{	't'	,	0x14	,	0	} ,
	{	'u'	,	0x16	,	0	} ,
	{	'v'	,	0x34	,	0	} ,
	{	'w'	,	0x11	,	0	} ,
	{	'x'	,	0x32	,	0	} ,
	{	'y'	,	0x15	,	0	} ,
	{	'z'	,	0x31	,	0	} ,
	{	'0'	,	0x0a	,	0	} ,
	{	'1'	,	0x01	,	0	} ,
	{	'2'	,	0x02	,	0	} ,
	{	'3'	,	0x03	,	0	} ,
	{	'4'	,	0x04	,	0	} ,
	{	'5'	,	0x05	,	0	} ,
	{	'6'	,	0x06	,	0	} ,
	{	'7'	,	0x07	,	0	} ,
	{	'8'	,	0x08	,	0	} ,
	{	'9'	,	0x09	,	0	} ,
	{	'-'	,	0x0b	,	0	} ,
	{	'='	,	0x0c	,	0	} ,
	{	'\\'	,	0x0d	,	0	} ,
	{	'['	,	0x1a	,	0	} ,
	{	']'	,	0x1b	,	0	} ,
	{	';'	,	0x29	,	0	} ,
	{	'\''	,	0x2a	,	0	} ,
	{	','	,	0x38	,	0	} ,
	{	'.'	,	0x39	,	0	} ,
	{	'/'	,	0x3a	,	0	} ,
	{	'`'	,	0x00	,	0	} ,
	{	'A'	,	0x20	,	1	} ,
	{	'B'	,	0x35	,	1	} ,
	{	'C'	,	0x33	,	1	} ,
	{	'D'	,	0x22	,	1	} ,
	{	'E'	,	0x12	,	1	} ,
	{	'F'	,	0x23	,	1	} ,
	{	'G'	,	0x24	,	1	} ,
	{	'H'	,	0x25	,	1	} ,
	{	'I'	,	0x17	,	1	} ,
	{	'J'	,	0x26	,	1	} ,
	{	'K'	,	0x27	,	1	} ,
	{	'L'	,	0x28	,	1	} ,
	{	'M'	,	0x37	,	1	} ,
	{	'N'	,	0x36	,	1	} ,
	{	'O'	,	0x18	,	1	} ,
	{	'P'	,	0x19	,	1	} ,
	{	'Q'	,	0x10	,	1	} ,
	{	'R'	,	0x13	,	1	} ,
	{	'S'	,	0x21	,	1	} ,
	{	'T'	,	0x14	,	1	} ,
	{	'U'	,	0x16	,	1	} ,
	{	'V'	,	0x34	,	1	} ,
	{	'W'	,	0x11	,	1	} ,
	{	'X'	,	0x32	,	1	} ,
	{	'Y'	,	0x15	,	1	} ,
	{	'Z'	,	0x31	,	1	} ,
	{	'!'	,	0x01	,	1	} ,
	{	'@'	,	0x02	,	1	} ,
	{	'#'	,	0x03	,	1	} ,
	{	'$'	,	0x04	,	1	} ,
	{	'%'	,	0x05	,	1	} ,
	{	'^'	,	0x06	,	1	} ,
	{	'&'	,	0x07	,	1	} ,
	{	'*'	,	0x08	,	1	} ,
	{	'('	,	0x09	,	1	} ,
	{	')'	,	0x0a	,	1	} ,
	{	'_'	,	0x0b	,	1	} ,
	{	'+'	,	0x0c	,	1	} ,
	{	'|'	,	0x0d	,	1	} ,
	{	'{'	,	0x1a	,	1	} ,
	{	'}'	,	0x1b	,	1	} ,
	{	':'	,	0x29	,	1	} ,
	{	'"'	,	0x2a	,	1	} ,
	{	'<'	,	0x38	,	1	} ,
	{	'>'	,	0x39	,	1	} ,
	{	'?'	,	0x3a	,	1	} ,
	{	'~'	,	0x00	,	1	} ,
	{	-1	,	-1	,	-1	}
};

struct MsgPort *port = NULL;
struct IOStdReq *req = NULL;

long errdev = 0;

int num_of_chrs;

struct InputEvent ie;

int really_open_window = 0;

do_args(c , v)
register int c;
register char *v[];
{
	register int i , j , k , s;
	register char chr;
	
	for (i = 1 ; i < c ; i++)
	{
		s = strlen(v[i]);

		for (j = 0 ; j < s ; j++)
		{
			if (v[i][j] == '\\' && v[i][j + 1] == 'n')
			{
				ie.ie_Qualifier = NULL;

				ie.ie_Code = 0x44;

				DoIO(req);

				ie.ie_Code = 0x44 | 0x80;

				DoIO(req);

				j += 2;
			}

			chr = v[i][j];

			for (k = 0 ; k != num_of_chrs ; k++)
				if (chrs[k].chr == chr)
				{
					fake_raw_key_event(k);
					
					break;
				}
		}
	}
}

fake_raw_key_event(c)
register char c;
{
	ie.ie_Qualifier = chrs[c].is_shifted ? IEQUALIFIER_LSHIFT : NULL;
	ie.ie_Code = chrs[c].raw_data;

	DoIO(req);

	ie.ie_Code |= 0x80;

	DoIO(req);
}

the_same()
{
	register int i;

	register PLANEPTR ptr1 , ptr2;

	ptr1 = cbm->Planes[0];
	ptr2 = tbm->Planes[0];

	for (i = 0 ; i != 16 ; i += 2)
		if (ptr1[i] != ptr2[i])
			return(0);

	return(1);
}

identify_char()
{
	register int c;

	for (c = 0 ; c != num_of_chrs ; c++)
	{
		cbm->Planes[0] = chrs[c].pln;

		if (the_same() )
			return(c);
	}

	return(-1);
}

convert_char(x , y)
register int x , y;
{
	register int rx , ry;

	register int c;

	rx = x - conUnit->cu_XROrigin;
	ry = y - conUnit->cu_YROrigin;

	rx &= ~7;
	ry &= ~7;

	rx += conUnit->cu_XROrigin;
	ry += conUnit->cu_YROrigin;

	ClipBlit(conWindow->RPort , (long) rx , (long) ry , trp , 0L , 0L , 8L , 8L ,
										0xC0L);

	if ( (c = identify_char() ) != -1)
		fake_raw_key_event(c);
}

main(argc , argv)
int argc;
char *argv[];
{
	register struct Window *win;
	register struct IntuiMessage *msg;
	register int x , y , code , qua;
	register long class;
	register int pressed = 0;
	register int rx , ry;
	register int prx = -1111 , fy , px = -1111 , maxx = -1111;
	register int i;
	register char buf[2];
	register long bl;
	register char string_buffer[50];

	puts("TextReader, by Oren Peli, Copyright (C) 1987 BazboSOFT!");

	for (i = 0 ; chrs[i].raw_data != -1 ; i++)
		chrs[i].pln = NULL;

	num_of_chrs = i - 1;

	if (NOT (IntuitionBase = (struct IntuitionBase *)
					OpenLibrary("intuition.library" , 33L) ) )
		bye();

	if (NOT findWindow() )
		bye();

	win = conWindow;

	sprintf(string_buffer , "TextReader's port (win:%lx)" , win);

	if (FindPort(string_buffer) )
	{
		puts("But you have already ran TextReader from this window!");

		bye();
	}

	if (NOT (port = CreatePort(string_buffer , 0L) ) )
		bye();

	if (NOT (req = CreateStdIO(port) ) )
		bye();

	if (errdev = OpenDevice("input.device" , 0L , req , 0L) )
		bye();

	if (NOT (GfxBase = (struct GfxBase *) OpenLibrary("graphics.library" , 33L) ) )
		bye();

	InitRastPort(trp);
	InitRastPort(crp);

	InitBitMap(tbm , 1L , 8L , 8L);
	InitBitMap(cbm , 1L , 8L , 8L);

	trp->BitMap = tbm;
	crp->BitMap = cbm;

	if (NOT (tbm->Planes[0] = AllocRaster(8L , 8L) ) )
		bye();

	SetAPen(trp , 0L);

	RectFill(trp , 0L , 0L , 8L , 8L);

	buf[1] = 0;

	SetAPen(crp , 1L);
	SetDrMd(crp , JAM2);

	bl = GfxBase->DefaultFont->tf_Baseline;

	for (i = 0 ; i != num_of_chrs ; i++)
	{
		cbm->Planes[0] = chrs[i].pln = AllocRaster(8L , 8L);

		if (NOT chrs[i].pln)
			bye();

		Move(crp , 0L , bl);

		buf[0] = chrs[i].chr;

		Text(crp , buf , 1L);
	}

	req->io_Command = IND_WRITEEVENT;
	req->io_Flags = 0;
	req->io_Length = (long) sizeof(struct InputEvent);
	req->io_Data = (void *) &ie;

	ie.ie_NextEvent = NULL;
	ie.ie_Class = IECLASS_RAWKEY;
	ie.ie_TimeStamp.tv_secs = 0;
	ie.ie_TimeStamp.tv_micro = 0;
	ie.ie_X = 0;
	ie.ie_Y = 0;

	ModifyIDCMP(win , MOUSEBUTTONS | MOUSEMOVE | MENUPICK);

	ReportMouse(TRUE , win);

	SetMenuStrip(win , &Menu);

	while (msg = GetMsg(win->UserPort) )
		ReplyMsg(msg);


	really_open_window = 1;

loop:
	WaitPort(win->UserPort);

	msg = GetMsg(win->UserPort);

	class = msg->Class;
	code = msg->Code;
	x = msg->MouseX;
	y = msg->MouseY;

	ReplyMsg(msg);

	Forbid();

	if (y < 10)
		win->Flags &= ~RMBTRAP;
	else
		win->Flags |= RMBTRAP;

	Permit();

	if (class == MENUPICK && code != MENUNULL)
		bye();

	else if (class == MOUSEBUTTONS)
	{
		if (code == SELECTDOWN)
		{
			ry = ( (fy = y) - conUnit->cu_YROrigin) / 8;
			pressed = 1;
		}

		else if (code == SELECTUP)
		{
			prx = -1111;
			px = -1111;
			maxx = -1111;

			pressed = 0;
		}

		else if (code == MENUDOWN)
		{
			rx = (x - conUnit->cu_XROrigin) / 8;
			ry = (y - conUnit->cu_YROrigin) / 8;

			ie.ie_Qualifier = NULL;

			if (ry > conUnit->cu_YCCP)
			{
				ie.ie_Code = 0x44;

				DoIO(req);

				ie.ie_Code = 0x44 | 0x80;

				DoIO(req);
			}

			else if (ry == conUnit->cu_YCCP)
			{
				if (rx > conUnit->cu_XCCP)
				{
					for (i = rx - conUnit->cu_XCCP + 1 ; i ; i--)
					{
						ie.ie_Code = 0x46;

						DoIO(req);

						ie.ie_Code = 0x46 | 0x80;

						DoIO(req);
					}
				}

				else if (rx < conUnit->cu_XCCP)
				{
					for (i = conUnit->cu_XCCP - rx ; i ; i--)
					{
						ie.ie_Code = 0x41;

						DoIO(req);

						ie.ie_Code = 0x41 | 0x80;

						DoIO(req);
					}
				}

				else if (rx == conUnit->cu_XCCP)
					do_args(argc , argv);
			}

			prx = -1111;
			px = -1111;
			maxx = -1111;

			pressed = 0;
		}
	}

	if (pressed && x >= conUnit->cu_XROrigin && y >= conUnit->cu_YROrigin && x <
				conUnit->cu_XRExtant && y < conUnit->cu_YRExtant)
	{
		rx = (x - conUnit->cu_XROrigin) / 8;

		if (rx != prx && rx > maxx)
		{
			maxx = rx;

			if (rx > prx && rx - prx > 1 && prx != -1111)
			{
				for (i = rx - prx + 1 , x = px + 8 ; i && x <
						conUnit->cu_XRExtant ; x += 8 , i--)
					convert_char(x , fy);
				
				x -= 8;
			}

			else
				convert_char(x , fy);

			rx = (x - conUnit->cu_XROrigin) / 8;

			if (rx > maxx)
				maxx = rx;

			prx = rx;

			px = x;
		}
	}

	goto loop;

	bye();
}

bye()
{
	register int i;

	for (i = 0 ; i != num_of_chrs ; i++)
		if (chrs[i].pln)
			FreeRaster(chrs[i].pln , 8L , 8L);

	if (tbm->Planes[0])
		FreeRaster(tbm->Planes[0] , 8L , 8L);

	if (conWindow && really_open_window)
	{
		Forbid();

		conWindow->Flags &= ~RMBTRAP;

		Permit();

		ClearMenuStrip(conWindow);

		ReportMouse(FALSE , conWindow);

		ModifyIDCMP(conWindow , NULL);
	}

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);

	if (GfxBase)
		CloseLibrary(GfxBase);

	if (NOT errdev && req)
		CloseDevice(req);

	if (req)
		DeleteStdIO(req);

	if (port)
		DeletePort(port);

	exit(0);
}

extern long sendpkt();

LONG findWindow() /* inits conWindow and conUnit (global vars) */
   {
   register struct InfoData *id;
	register    struct MsgPort  *conid;
	register    struct Process  *me;
	register   LONG myargs[8] ,nargs, res1;

   /* Alloc to insure longword alignment */
   id = (struct InfoData *)AllocMem( (long) sizeof(struct InfoData),
                                       MEMF_PUBLIC|MEMF_CLEAR);
   if(! id) return(0);
   me = (struct Process *) FindTask(NULL);
   conid = (struct MsgPort *) me->pr_ConsoleTask;

   myargs[0]=((ULONG)id) >> 2;
   nargs = 1;
   res1 = (LONG)sendpkt(conid,ACTION_DISK_INFO,myargs,nargs);
   conWindow = (struct Window *)id->id_VolumeNode;
   conUnit = (struct ConUnit *)
                 ((struct IOStdReq *)id->id_InUse)->io_Unit;
   FreeMem(id, (long) sizeof(struct InfoData));
   return(res1);
}


LONG sendpkt(pid,action,args,nargs)
register struct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
register LONG action,          /* packet type ... (what you want handler to do )   */
     args[],          /* a pointer to a argument list */
     nargs;           /* number of arguments in list  */
   {
	register    struct MsgPort        *replyport;
   struct StandardPacket *packet;
 
	register    LONG  count, *pargs, res1;

   replyport = (struct MsgPort *) CreatePort( (long) NULL, (long) 0);
   if(!replyport) return( (long) NULL);

   packet = (struct StandardPacket *) 
      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
   if(!packet) 
      {
      DeletePort(replyport);
      return(NULL);
      }

   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
   packet->sp_Pkt.dp_Port         = replyport;
   packet->sp_Pkt.dp_Type         = action;

   /* copy the args into the packet */
   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
   for(count=0;count < nargs;count++) 
      pargs[count]=args[count];
 
   PutMsg(pid,packet); /* send packet */

   WaitPort(replyport);
   GetMsg(replyport); 

   res1 = packet->sp_Pkt.dp_Res1;

   FreeMem(packet,(long)sizeof(struct StandardPacket));
   DeletePort(replyport); 

   return(res1);
}
