#include <qd.h>
#include <qdvars.h>
#include <win.h>

#include "mactials.h"
#include "messages.h"
#include "crab.h"
#include "board.h"
#include "tiles.h"

#define PAINTWHITE	(*((int *) 0x9DC))

#define PASTRUE		(0x100)
#define PASFALSE	0

grafptr screenport;
windowptr mainwindow, dictwindow, newdictwindow ();
windowrecord wrecord;

rgnhandle utilrgn;
rgnhandle backrgn;

rect screenrect;

rect boardrect;
rect rackrect;
rect backrect;

#define TTABLE	0
#define TBOARD	1
#define TRACK	2
#define TBACK	3

bitmap *tialpix;
bitmap *numpix;
bitmap *squarepix;
bitmap *rackpix;
bitmap *backpix;

setupwindows ()
{
	getwmgrport (&screenport);
	screenrect = screenbits.bounds;
	screenrect.a.top += 20;
	PAINTWHITE = PASFALSE;
	mainwindow = newwindow (&wrecord, &screenrect, "", 1, plaindbox, 
		(windowptr) -1, 0, 0L);
	dictwindow = newdictwindow ();
	PAINTWHITE = PASTRUE;
	setport (mainwindow);
	noclip ();
	utilrgn = newrgn ();
	textfont (systemfont);
	textmode (srcbic);
}

getpix ()
{
	bitmap *getbitmap ();

	tialpix = getbitmap ("Tiles");
	numpix = getbitmap ("Numbers");
	squarepix = getbitmap ("Squares");
	rackpix = getbitmap ("Rackfront");
	backpix = getbitmap ("Rackback");

	rackrect.a.right =  mainwindow -> portrect.a.right;
	rackrect.a.bottom = mainwindow -> portrect.a.bottom - 
		rackpix -> bounds.a.bottom;
	rackrect.a.left = rackrect.a.right - rackpix -> bounds.a.right;
	rackrect.a.top = rackrect.a.bottom - rackpix -> bounds.a.bottom;
	backrect = rackrect;
	backrect.a.top = mainwindow -> portrect.a.top + 
		rackpix -> bounds.a.bottom;
	backrect.a.bottom = backrect.a.top + rackpix -> bounds.a.bottom;
	backrgn = newrgn ();
	rectrgn (backrgn, &backrect);
	setrect (&boardrect, B, B, B + LEN * T, B + LEN * T);
}

mywin (win) register windowptr win;
{
	extern windowptr tiledial;
	return (win == mainwindow || win == dictwindow || win == tiledial);
}

wintasks (fw) register windowptr fw;
{
	if (fw == dictwindow)
		dicttask ();
}

winclick (win, where, mods) windowptr win; point *where; int mods;
{
	if (win == mainwindow)
		userclick (where);
	else if (win == dictwindow)
		dictclick (where, mods);
}

winkey (win, c, where) windowptr win; char c; point *where;
{
	if (win == dictwindow) 
		dictkey (c);
	else 
		userkey (c, where);
}

winrefresh ()
{
	pushmain ();
	invalrect (&mainwindow -> portbits.bounds);
	popport ();
	winupdate (mainwindow);
}

extern int playing, firstgame;

winupdate (win) register windowptr win;
{
	beginupdate (win);
	pushport (win);
	if (win == mainwindow) {
		fillrgn (mainwindow -> visrgn, black);
		newscores ();
		drawracks (&mainwindow -> portbits);
		hlock (mainwindow -> visrgn);
		drawboard (&(*(mainwindow -> visrgn)) -> rgnbbox, &mainwindow -> portbits);
		hunlock (mainwindow -> visrgn);
		if (playing)
			clipout (backrgn);
		drawtials (&mainwindow -> portbits);
		noclip ();
	}
	else if (win == dictwindow)
		dictupdate ();
	popport ();
	endupdate (win);
}

winactivate (win, yesno) register windowptr win; int yesno;
{
	if (win == dictwindow)
		dictactivate (yesno);
}

pushmain ()
{
	pushport (mainwindow);
}

drawracks (screen) register bitmap *screen;
{
	copybits (rackpix, screen, &rackpix -> bounds, &rackrect, srccopy, 0L);
	copybits (backpix, screen, &backpix -> bounds, &backrect, srccopy, 0L);
}

static int mydscore = -1, yourdscore = -1;

newscores ()
{
	rect r;

	pushport (mainwindow);
	if (players[ME].score != mydscore) {
		setrect (&r, backrect.a.left, 0,
			backrect.a.right, backrect.a.top - 4);
		fillrect (&r, black);
	}
	if (players[YOU].score != yourdscore) {
		setrect (&r, rackrect.a.left, rackrect.a.bottom,
			backrect.a.right, rackrect.a.bottom + 20);
		fillrect (&r, black);
	}
	drawscores ();
	popport ();
}

drawscores ()
{
	point end;

	if (!playing && firstgame)
		return;
	end.a.h = (backrect.a.left + backrect.a.right) / 2;

	end.a.v = backrect.a.top - 6;
	numput (players[ME].score, &end, 1);
	mydscore = players[ME].score;
	end.a.v = rackrect.a.bottom + 18;
	numput (players[YOU].score, &end, 1);
	yourdscore = players[YOU].score;
}

numput (n, end, rjust) int n; point *end; int rjust;
{
	char buf[8];
	point start;

	start = *end;
	numtostring ((long) n, buf);
	if (rjust)
		start.a.h -= stringwidth (buf);
	moveto (start.a.h, start.a.v);
	drawstring (buf);
	
}

drawboard (bounds, screen) register rect *bounds; register bitmap *screen;
{
	register int i, j;
	int ilo, ihi, jlo, jhi;
	rect r;
	penstate pn;

	getpenstate (&pn);
	r = boardrect;
	insetrect (&r, -2, -2);
	penmode (patbic);
	framerect (&r);
	setpenstate (&pn);
	pointboardpos (&bounds -> b.topleft, &ilo, &jlo);
	pointboardpos (&bounds -> b.botright, &ihi, &jhi);
	for (i = ilo; i <= ihi; i++)
		for (j = jlo; j <= jhi; j++)
			drawsquare (i, j, 1, screen);
}

drawsquare (i, j, above, screen) register int i, j; int above; bitmap *screen;
{
	rect q, r;
	int pos;
	char what;
	register bitmap *pix;

	pos = POSITION (ACROSS, i, j);
	what = board[pos];
	if (what && above) {
		pix = tialpix;
		tilerect (&r, what);
	}
	else {
		pix = squarepix;
		squarerect (&r, pos);
	}
	boardposrect (&q, i, j);
	copybits (pix, screen, &r, &q, srccopy, 0L);
}

adjust (n) register int *n;
{
	if (*n < 1)
		*n = 1;
	else if (*n > LEN)
		*n = LEN;
}

squarerect (r, pos) register rect *r; register int pos;
{
	register int x;

	x = lettermult[pos];
	if (pos == CENTER)
		x = 6;
	else if (wordmult[pos] > 1)
		x = 2 + wordmult[pos];
	nthtialrect (x, r);
}

tilerect (r, what) register rect *r; register char what;
{
	register int n;

	n = letr (what);
	numbertial (n, !blank (what));
	nthtialrect (n, r);
}

tialboardpos (t) tial *t;
{
	int i, j;

	rectboardpos (&t -> ubits.bounds, &i, &j);
	return POSITION (ACROSS, i, j);
}

rectboardpos (r, i, j) rect *r; int *i, *j;
{
	point center;

	rectcenter (r, &center);
	pointboardpos (&center, i, j);
}

pointboardpos (p, i, j) point *p; register int *i, *j;
{
	point where;

	where = *p;
	subpt (&boardrect.b.topleft, &where);
	*j = where.a.h / T + 1;
	*i = where.a.v / T + 1;
	adjust (i);
	adjust (j);
}

alloctialbits (b) register bitmap *b;
{
	bitmap foo;
	extern rect tialrect;

	foo.bounds = tialrect;
	allocbitmap (&foo);
	b -> rowbytes = foo.rowbytes;
	b -> baseaddr = foo.baseaddr;
}

boardposrect (r, i, j) register rect *r; register int i, j;
{
	r -> a.right = B + j * T;
	r -> a.left = r -> a.right - T;
	r -> a.bottom = B + i * T;
	r -> a.top = r -> a.bottom - T;
}

rectfrompos (r, pos) rect *r; register int pos;
{
	if (XPOSED (pos))
		pos = TRANSPOSE (pos);
	boardposrect (r, ROW (pos), COLUMN (pos));
}

fixboard (pos) register int pos;
{
	rect r;
	tial *t;
	extern tial *tials;
	int n;

	rectfrompos (&r, pos);
	n = olap (0L, &r);
	if (n)
		tials[n - 1].flags = FIXED;
	pushport (mainwindow);
	invalrect (&r);
	popport ();
}

droprack (t, rk, angle) tial *t; rect *rk; char angle;
{
	rect r;

	goalshape.angle = angle;
	goalshape.size = LARGE;
	r.a.top = rk -> a.top - 3 - T;
	r.a.bottom = r.a.top + T;
	r.a.left = rackgap (t, rk);
	r.a.right = r.a.left + T;
	smoothmove (t, &r);
	offsetrect (&r, 0, T);
	clipout (backrgn);
	rackinsert (t, &r, rk);
	noclip ();
	return 1;
}

trydropinrack (t) tial *t;
{
	rect r;

	shaperect (FACEUP, LARGE, &t -> ubits.bounds, &r);
	r.a.top = rackrect.a.top - 3;
	r.a.bottom = r.a.top + T;
	rackinsert (t, &r, &rackrect);
	return 1;
}

trydroponboard (t) register tial *t;
{
	rect r;
	int i, j;

	rectboardpos (&t -> ubits.bounds, &i, &j);
	if (board[POSITION (ACROSS, i, j)])
		return 0;
	boardposrect (&r, i, j);
	if (olapshape (t, &r, FACEUP, LARGE))
		return 0;
	goalshape.size = LARGE;
	goalshape.angle = FACEUP;
	smoothmove (t, &r);
	t -> flags |= HILITE;
	refreshtial (t);
	return 1;
}
	
trydropontable (t) register tial *t;
{
	if (olapshape (t, &t -> ubits.bounds, FACEUP, SMALL))
		return 0;
	goalshape.size = SMALL;
	return 1;
}

trydrop (t) register tial *t;
{
	extern int newt, whoseturn;
	int where = twhere (t);

	if (t -> flags & SOCK) {
		if (where == TRACK)
			trydropinrack (t);
		else
			droprack (t, &rackrect, FACEUP);
		t -> flags &= ~SOCK;
		if (!newt)
			fliptrade ();
		return 1;
	}
	
	if (newt || whoseturn != YOU) {
		if (where == TRACK)
			return trydropinrack (t);
		return 0;
	}
	
	switch (where) {
		case TTABLE:
			return trydropontable (t);
		case TRACK:
			return trydropinrack (t);
		case TBACK:
			return 0;
		case TBOARD:
			return trydroponboard (t);
	}
}

twhere (t) register tial *t;
{
	if (t -> ubits.bounds.a.left - 2 < boardrect.a.right)
		return TBOARD;
	if (t -> ubits.bounds.a.bottom + 4 > rackrect.a.top)
		return TRACK;
	if (t -> ubits.bounds.a.top - 4 < backrect.a.bottom)
		return TBACK;
	return TTABLE;
}

trypick (t) register tial *t;
{
	int fromsock = 0;
	
	if (t -> flags & MINE || (fromsock = tialchoose (t))) {
		goalshape.angle = FACEUP;
		goalshape.size = LARGE;
		t -> flags = fromsock ? (SOCK + MINE) : MINE;
		refreshtial (t);
		return 1;
	}
	return 0;
}

backpick (t) register tial *t;
{
	rect r;
	
	goalshape.angle = FACEUP;
	goalshape.size = LARGE;
	r = t -> ubits.bounds;
	offsetrect (&r, 0, -T);
	clipout (backrgn);
	smoothmove (t, &r);
	noclip ();
}

whatsunder (tp) register tial *tp;
{
	bitmap savebits;
	int i, j;
	point center;

	savebits = theport -> portbits;
	alloctialbits (&tp -> ubits);
	setportbits (&tp -> ubits);
	fillrect (&tp -> ubits.bounds, black);
	setportbits (&savebits);
	rectcenter (&tp -> ubits.bounds, &center);
	if (ptinrect (&center, &boardrect)) {
		pointboardpos (&center, &i, &j);
		drawsquare (i, j, 0, &tp -> ubits);
	}
	else if (ptinrect (&center, &rackrect) || ptinrect (&center, &backrect))
		drawracks (&tp -> ubits);
}

clipout (r) rgnhandle r;
{
	diffrgn (mainwindow -> cliprgn, r, mainwindow -> cliprgn);
}

noclip ()
{
	rectrgn (mainwindow -> cliprgn, &mainwindow -> portrect);
}
