/* Include file for turtle.c for AMIGA */
/* July '87 - Scott Evernden */

#if 1
#define LOGGER(b)
#else
#define LOGGER(b)	{ printf b; fflush(stdout); }
#endif


#include <math.h>
#include "logo.h"
#include "amiga.h"

struct Task *FindTask();
APTR origExceptCode, origExceptData;
int origExceptSigs;

extern void *IconBase;
extern struct WBStartup *WBenchMsg;
static int from_wb;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Region *region, *NewRegion();
struct Library *LayersBase, *OpenLibrary();
struct Window *twin, *OpenWindow();

struct NewWindow new_twin = {
	640 - (4 + 400 + 4), 0,
	4 + 400 + 4, 11 + 172 + 2,
	-1, -1,
	0,
	WINDOWDRAG | WINDOWDEPTH | SMART_REFRESH | NOCAREREFRESH,
	NULL, NULL, 
	(UBYTE *) "LOGO Turtle Window",
	NULL, NULL, 
	100, 100,
	999, 999,
	WBENCHSCREEN
};


char editor_name[64];

static struct Task *myTask;
static int centx, centy;	/* turtle window center */

struct RastPort *rp;
struct Window *w;

extern int penerase;
extern NUMBER yscrunch;
extern struct display *mydpy, amiga;

extern struct Task *FindTask();

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

amgturt(hide)
int hide;	/* nonzero to erase turtle */
{
	long sx,sy,x,y;
	double angle;

LOGGER(("amgturt(%d): ", hide));

	SetDrMd(rp,COMPLEMENT);

	angle = mydpy->turth*(3.141592654/180.0);
	sx = x = mydpy->turtx + 15.0*sin(angle);
	sy = y = yscrunch * (mydpy->turty + 15.0*cos(angle));
LOGGER(("(%d,%d)",x,y));
	Move(rp,centx+x,centy-y);

	angle = (mydpy->turth-90.0)*(3.141592654/180.0);
	x = mydpy->turtx + 15.0*sin(angle);
	y = yscrunch * (mydpy->turty + 15.0*cos(angle));
LOGGER(("(%d,%d)",x,y));
	Draw(rp,centx+x,centy-y);

	angle = (mydpy->turth+90.0)*(3.141592654/180.0);
	x = mydpy->turtx + 15.0*sin(angle);
	y = yscrunch * (mydpy->turty + 15.0*cos(angle));
LOGGER(("(%d,%d)",x,y));
	Draw(rp,centx+x,centy-y);

LOGGER(("(%d,%d)\n",sx,sy));
	Draw(rp,centx+sx,centy-sy);
	WritePixel(rp,centx+sx,centy-sy);
}

amgfrom(x,y)
NUMBER x,y;
{
LOGGER(("amgfrom(%d,%d)\n", (long)x,(long)y));
	Move(rp,centx+(long)x,centy-(long)y);
}

amgto(x,y)
NUMBER x,y;
{
	static long amgpens[] = {JAM1,JAM1|INVERSVID,COMPLEMENT};

LOGGER(("amgto(%d,%d)\n", (long)x,(long)y));
	SetDrMd(rp,amgpens[penerase]);
	Draw(rp,centx+(long)x,centy-(long)y);
}

amgin()
{
	struct Rectangle rect;
	int t, wid, hyt;

LOGGER(("amgin()\n"));

	if (twin)
		return;

	twin = OpenWindow(&new_twin);
	if (!twin)
		fault("opening turtle window");

	rp = twin->RPort;
	SetAPen(rp, 1L);

	rect.MinX = twin->BorderLeft;
	rect.MinY = twin->BorderTop;
	rect.MaxX = twin->Width - twin->BorderRight,
	rect.MaxY = twin->Height - twin->BorderBottom;

LOGGER(("min (%d,%d) - max (%d,%d)\n",
		rect.MinX, rect.MinY, rect.MaxX, rect.MaxY));

	ClearRegion(region);
	OrRectRegion(region, &rect);
	InstallClipRegion(rp->Layer, region);

	wid = rect.MaxX - rect.MinX;
	hyt = rect.MaxY - rect.MinY;

	t = wid / 2;
	centx = twin->BorderLeft + t;
	mydpy->xlow = -t;
	mydpy->xhigh = wid - t;

	t = hyt / 2;
	centy = twin->BorderTop + t;
	mydpy->ylow = (-t) / mydpy->stdscrunch;
	mydpy->yhigh = (hyt - t) / mydpy->stdscrunch;

LOGGER(("center (%d,%d)\n", centx, centy));
LOGGER(("xlow,ylow (%d,%d)\n", (int)mydpy->xlow, (int)mydpy->ylow));
LOGGER(("xhigh,yhigh (%d,%d)\n", (int)mydpy->xhigh, (int)mydpy->yhigh));

}

amgout()
{
LOGGER(("amgout()\n"));

	if (!twin)
		return;

	InstallClipRegion(rp->Layer, (struct Region *) NULL);
	CloseWindow(twin);
	twin = rp = NULL;
}

amgpenc(ipen)
int ipen;
{
LOGGER(("amgpenc(%d)\n",ipen));

	if (ipen<0 || ipen>3) {
		puts("The pen color must be 0 to 3.");
		errhand();
	}
	SetAPen(rp,(long)ipen);
}

amgstate(which)
{
LOGGER(("amgstate(%c)\n", which));
	if (!rp)
		return;

	switch (which) {
	case 'c':
	case 'w':
		SetRast(rp, 0L);
		break;

	case 'f':
	case 's':
		printf("Hey, I am NOT an Atari computer!\n");
		errhand();
		break;
	}
}

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

wb_start()
{
	char *cp;
	struct DiskObject *dop;

	from_wb++;

	IconBase = OpenLibrary("icon.library", 0L);
	if (!IconBase)
		fault("opening icon library");

	dop = GetDiskObject(WBenchMsg->sm_ArgList->wa_Name);
	if (dop) {
		cp = FindToolType(dop->do_ToolTypes, "EDITOR");
		if (cp)
			strcpy(editor_name, cp);
		FreeDiskObject(dop);
	}
	CloseLibrary(IconBase);
}


amiga_start(argc, argv)
int argc;
char *argv[];
{
	extern int Enable_Abort, exceptSig, exceptCode();

	Enable_Abort = 0;

	if (argc == 0)
		wb_start();

	myTask = FindTask((char *) NULL);

	origExceptCode = myTask->tc_ExceptCode;
	origExceptData = myTask->tc_ExceptData;
	origExceptSigs = SetExcept(-1, 0);

	myTask->tc_ExceptCode = (APTR) exceptCode;
	myTask->tc_ExceptData = (APTR) &exceptSig;

	IntuitionBase = (struct IntuitionBase *)
						OpenLibrary("intuition.library", 0L);
	if (!IntuitionBase)
		fault("opening intuition");

	GfxBase = (struct GfxBase *)
						OpenLibrary("graphics.library", 0L);
	if (!GfxBase)
		fault("opening graphics");

	if (GfxBase->Modes & INTERLACE) {
		new_twin.Height = 11 + 344 + 2;
		amiga.ylow = -172.0;
		amiga.yhigh = 172.0;
		amiga.stdscrunch = .86;
	}

	LayersBase = OpenLibrary("layers.library", 33L);
	if (!LayersBase)
		fault("opening layers");

	region = NewRegion();
	if (!region)
		fault("opening region");
}

amiga_end()
{
	amgout();

	if (region)
		DisposeRegion(region);

	if (LayersBase)
		CloseLibrary(LayersBase);

	if (GfxBase)
		CloseLibrary(GfxBase);

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);

	SetExcept(0, -1);

	myTask->tc_ExceptCode = origExceptCode;
	myTask->tc_ExceptData = origExceptData;

	SetExcept(origExceptSigs, -1);
}

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

/* replacement _abort */
_abort()
{
	amiga_end();
	exit(0);
}

abort()
{
	_abort();
}

fault(msg)
char *msg;
{
	printf("Error %s.\n", msg);
	fflush(stdout);
	amiga_end();
	exit(0);
}

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

int quitsig = 0;
int exceptSig = 0;
int exceptSigs = 0;
int exceptFlag = 0;
int (*intrCode)();
int (*quitCode)();

#asm

	public	_exceptCode
	public	_geta4
	public	_exceptHandler

_exceptCode:
	move.l	d0,(a1)
	jsr	_geta4
	jsr	_exceptHandler
	rts

#endasm


exceptHandler()	
{
	int (*efunc)();
	int sigpaws(), sigquit();

	exceptFlag = 1;
	exceptSigs &= ~exceptSig;	/* simulate signal behaviour */

	efunc = exceptSig == SIGBREAKF_CTRL_D ? intrCode : quitCode;

	if (efunc == sigquit)
		quitsig++;
	else
		sigpaws();

LOGGER(("exceptHandler returns %lx\n", exceptSigs));
	exceptFlag = 0;
	return exceptSigs;
}

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

signal(sig, func)
int sig, (*func)();
{
	int exceptKey;

LOGGER(("signal() call; sig %d; flag %d\n", sig, exceptFlag));

	if (sig == SIGINT) {
		exceptKey = SIGBREAKF_CTRL_D;
		intrCode = func;
	}
	else {
		exceptKey = SIGBREAKF_CTRL_C;
		quitCode = func;
	}

	exceptSigs |= exceptKey;

	if (!exceptFlag)
		SetExcept(exceptKey, exceptKey);

LOGGER(("signal() returns\n"));
}

/*******************************************************************/
/* AMIGA specific LOGO keyword commands go here: */


struct object *chdir(cmd)
register struct object *cmd;
{
	register struct object *str;

	str = stringform(cmd);
	if (!cd(str->obstr)) {
		printf("Can't chdir to %s\n", str->obstr);
		errhand();
	}
	return ((struct object *)(-1));
}

static cd(name)
char *name;
{
	struct FileInfoBlock *AllocMem();
	struct FileLock *Lock(), *CurrentDir();
	struct FileInfoBlock *fib;
	struct FileLock *oldlock, *filelock;
	int ok;

	ok = 0;
	if (filelock = Lock(name, ACCESS_READ)) {
		if (fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)) {
			if (Examine(filelock, fib)) {
				if (0 <= fib->fib_DirEntryType) {
					if (oldlock = CurrentDir(filelock)) {
						UnLock(oldlock);
						ok++;
					}
				}
			}
			FreeMem(fib, sizeof(*fib));
		}
	}
	if (!ok)
		UnLock(filelock);
	return ok;
}

