/*
 * A simple curses emulation for the Amiga, specifically for WANDERER
 *
 * Alan Bland
 */
#ifdef AMIGA

#include <stdio.h>
#include <ctype.h>
#include <curses.h>

#include <dos.h>
#include <intuition/intuition.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/memory.h>

#include <proto/exec.h>
#include <proto/intuition.h>

/* generated by Power Windows 2.0 */
#include "pw.palette.h"
#include "pw.menus.h"

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Screen *S;
struct Window *W;
struct RastPort *R;
struct TextFont *map_font, *text_font;
struct Library *DiskfontBase;

#define TOPEDGE 12	/* how much of screen bar to show */
int WindowWidth = 640;
int WindowHeight = 200 - TOPEDGE;

int MouseX, MouseY;

/* getmouse - get current row and column of mouse */
getmouse(amr,amc)
int *amr;
int *amc;
{
	*amr = MouseY / 8;
	*amc = MouseX / 8;
}

/* Return when either a console key or mouse button is pressed. */
mouseorkey()
{
	return nextevent(MOUSEBUTTONS | RAWKEY | MENUPICK, 1);
}

flushinput()
{
	while (nextevent(RAWKEY, 0) >= 0) ;
}

/* returns next character, with special WANDERER translations */
getch()
{
	return nextevent(RAWKEY | MENUPICK, 1);
}

/* returns next character with no special translations */
/* used mainly for getstr() */
getvanillach()
{
	return nextevent(VANILLAKEY, 1);
}

cursor(state)
int state;
{
	int x, y;
	x = R->cp_x;
	y = R->cp_y - R->Font->tf_Baseline;
	SetDrMd(R, COMPLEMENT);
	RectFill(R, x, y, x+8, y+R->Font->tf_YSize-1);
	SetDrMd(R, JAM2);
}

/* special keymap for wanderer raw mode - translates function keys and
 * cursor keys to wanderer single-key commands */
char mykeys[] = {
	'`','1','2','3','4','5','6','7','8','9','0','-','=','\\',0,0,
	'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'j',0,
	'a','s','d','f','g','h','j','k','l',';','\'',0,0,'h','@','l',
	0,'z','x','c','v','b','n','m',',','.','/',0,0,0,'k',0,
	' ','\b',0,'\n','\n','q',0,0,0,0,0,0,'k','j','l','h',
	'~','#','@',0,0,'S','R',0,0,'!',0,0,0,0,0,'?',
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
char myshiftkeys[] = {
	'~','!','@','#','$','%','^','&','*','(',')','_','+','|',0,0,
	'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,0,0,
	'A','S','D','F','G','H','J','K','L',':','"',0,0,0,0,0,
	0,'Z','X','C','V','B','N','M','<','>','?',0,0,0,0,0,
	' ','\b',0,'\n','\n',0,0,0,0,0,0,0,'k','j','l','h',
	'~','#','@',0,0,'S','R',0,0,'!',0,0,0,0,0,'?',
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

nextevent(flags, wait)
long flags;
int wait;
{
	register int class, code;
	register struct IntuiMessage *message;
	int result, qual;

	/* show cursor if inputting a stream of text */
	if (flags & VANILLAKEY) cursor(1);
	ModifyIDCMP(W, CLOSEWINDOW | flags);
	while (1)
	{
		if (wait)
		{
		    /* get next event, waiting if none are available */
		    while ((message = (struct IntuiMessage *)GetMsg(W->UserPort)) == NULL)
		    {
			Wait(1<<W->UserPort->mp_SigBit);
		    }
		}
		else
		{
		    /* get next event, but return if none are available */
		    message = (struct IntuiMessage *)GetMsg(W->UserPort);
		    if (message == NULL)
		    {
			result = -1;
			break;
		    }
		}
		class = message->Class;
		code = message->Code;
		qual = message->Qualifier;
		MouseX = message->MouseX;
		MouseY = message->MouseY;
		ReplyMsg((struct Message *)message);

		switch (class)
		{
		case CLOSEWINDOW:
			/* ignore for now */
			continue;
		case VANILLAKEY:
			result = code;
			if (result == '\r') result = '\n';
			break;
		case RAWKEY:
			if (code&0x80) continue;	/* ignore key releases */
			/* only recognize wanderer keys */
			/* can use cursor keys, hjkl, ibm keypad for moving */
			if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
				result = myshiftkeys[code];
			else
				result = mykeys[code];
			if (result == 0) continue;	/* ignore undef keys */
			break;

		case MENUPICK:
			if (code == MENUNULL) continue;
			switch (MENUNUM(code)) {
			case 0:
				switch (ITEMNUM(code)) {
				case 0:		result = 'W'; break;
				case 1:		result = 'S'; break;
				case 2:		result = 'R'; break;
				case 4:		result = 'c'; break;
				case 5:		result = 'q'; break;
				default:	continue;
				}
				break;
			case 1:
				switch (ITEMNUM(code)) {
				case 0:		result = '~'; break;
				case 1:		result = '#'; break;
				case 2:		result = '@'; break;
				case 3:		result = '!'; break;
				case 4:		result = '?'; break;
				default:	continue;
				}
				break;
			default:
				continue;
			}
			break;

		case MOUSEBUTTONS:
			switch (code)
			{
			case SELECTDOWN:
				break;	/* left button pressed */
			default:
				continue; /* ignore button releases */
			}
			result = MOUSE;
			break;
		default:
			continue;
		}
		break;
	}
	/* turn off cursor if it was on */
	if (flags & VANILLAKEY) cursor(0);
	return result;
}

struct TextAttr font =
{
	"topaz.font",TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT
};

struct NewScreen ns =
{
	0,0,640,200,4,BLACK,WHITE,HIRES,CUSTOMSCREEN,&font,"Wanderer V2.2",NULL,NULL
};

initscr()
{
	struct NewWindow nw;
	struct TextAttr font_attr;

	if (S != NULL) return;

	IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0);
	GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0);
	if (IntuitionBase == NULL || GfxBase == NULL) exit(1);

	/* load the digitized sound effects (yeah, what's it doing here?) */
	initSounds();

	/* load the map font */
	DiskfontBase = (struct Library *) OpenLibrary("diskfont.library",0);
	font_attr.ta_Name = "wanderer.font";
	font_attr.ta_YSize = 8;
	font_attr.ta_Style = 0;
	font_attr.ta_Flags = 0;
	map_font = (struct TextFont *) OpenDiskFont(&font_attr);

	if ((S = (struct Screen *) OpenScreen(&ns)) == NULL) exit(1);

	nw.LeftEdge = 0;
	nw.TopEdge = TOPEDGE;
	nw.Width = WindowWidth;
	nw.Height = WindowHeight;
	nw.DetailPen = BLACK;
	nw.BlockPen = WHITE;
	nw.Title = NULL;
	nw.Flags = SMART_REFRESH | ACTIVATE | BACKDROP |
		   BORDERLESS | NOCAREREFRESH;
	nw.IDCMPFlags = RAWKEY;
	nw.Type = CUSTOMSCREEN;
	nw.FirstGadget = NULL;
	nw.CheckMark = NULL;
	nw.Screen = S;
	nw.BitMap = NULL;
	if ((W = (struct Window *) OpenWindow(&nw)) == NULL) exit(1);
	R = W->RPort;

	/* setup colors */
	LoadRGB4(&S->ViewPort, Palette, PaletteColorCount);

	/* keep track of original font */
	text_font = R->Font;

	SetAPen(R, TEXT_COLOR);
	SetBPen(R, BACK_COLOR);
	ShowTitle(S, FALSE);
	SetMenuStrip(W, &MenuList1);
	clear();
}

move(r,c)
int r,c;
{
	Move(R, c*8, r*8 + R->Font->tf_Baseline);
}

eraseeol()
{
	int x, y;
	x = R->cp_x;
	y = R->cp_y  - R->Font->tf_Baseline;
	SetAPen(R, BACK_COLOR);
	RectFill(R, x, y, WindowWidth, y+R->Font->tf_YSize-1);
	SetAPen(R, TEXT_COLOR);
}

eraserow(r)
{
	move(r,0);
	eraseeol();
}

endwin()
{
	freeSounds(NULL);
	if (map_font) CloseFont(map_font);
	if (W) { ClearMenuStrip(W); CloseWindow(W); }
	if (S) CloseScreen(S);
}

set_map_font(flag)
int flag;
{
	if (flag) SetFont(R, map_font);
	else SetFont(R, text_font);
}

clear()
{
	SetAPen(R, BACK_COLOR);
	RectFill(R, 0, 0, WindowWidth, WindowHeight);
	SetAPen(R, TEXT_COLOR);
	move(0,0);
}

/* get a line of input from the console, handling backspaces */
/* menus are disable while inputting */
getstr(s)
char *s;
{
	char *origs = s;
	int c;

	ClearMenuStrip(W);
	SetAPen(R, INPUT_COLOR);
	while ( (c=getvanillach()) != '\n' && c!='\r' && c!= EOF ) {
		if ( c == '\b' ) {
			if ( s > origs ) {
				addstr("\b \b");
				s--;
			}
		}
		else if (c == 24) {
			while (s > origs) {
				addstr("\b \b");
				s--;
			}
		} else if (isprint(c)) {
			addch(c);
			*s++ = c;
		}
		refresh();
	}
	*s = '\0';
	SetAPen(R, TEXT_COLOR);
	SetMenuStrip(W, &MenuList1);
}

addstr(s)
char *s;
{
	/* output is fastest if is many chars as possible can be */
	/* displayed in a single Text() call, so we scan for special */
	/* characters that need to be interpreted, and do the rest */
	/* in as few Text() calls as possible */
	register int i,a;
	for (i=0,a=0; ; ++i) {
		if (s[i] < ' ') {
			/* special character found */
			/* output everything up to this character */
			if (i-a>0) Text(R, s+a, i-a);
			/* interpret the special character */
			if (s[i] == 0) break;
			addch(s[i]);
			/* continue after the special character */
			a = i+1;
		}
	}
}

addch(c)
int c;
{
	char s;
	switch (c) {
	case '\n':
		Move(R, 0, R->cp_y + 8);
		break;
	case '\r':
		Move(R, 0, R->cp_y);
		break;
	case '\t':
		Move(R, R->cp_x + 64 - (R->cp_x % 64), R->cp_y);
		break;
	case '\b':
		Move(R, R->cp_x - 8, R->cp_y);
		break;
	case '\007':
		DisplayBeep(S);
		break;
	default:
		s = c;
		Text(R, &s, 1);
		break;
	}
}

struct IntuiText fataltext = { 1,0,COMPLEMENT,16,32,NULL,NULL,NULL };
struct IntuiText canceltext = { 1,0,COMPLEMENT,2,2,NULL,"goodbye",NULL };

fatal(text)
char *text;
{
	fataltext.IText = text;
	AutoRequest(W, &fataltext, NULL, &canceltext, 0, 0, 320, 90);
	endwin();
	exit(1);
}

#endif
