#include <qd.h>
#include "mactials.h"
#include "crab.h"
#include "tiles.h"
#include "board.h"

extern grafptr mainwindow;

bitmap workbits;
bitmap sparebits;

extern bitmap *numpix, *tialpix;

tial *tials;
int tialcount;

rect tialrect;

tialshape goalshape;

char *malloc ();

createtials ()
{
	setrect (&tialrect, 0, 0, T, T);
	sparebits.bounds = tialrect;
	allocbitmap (&sparebits);
	setrect (&workbits.bounds, 0, 0, 2 * T, 2 * T);
	allocbitmap (&workbits);
	
	tials = (tial *) malloc (MAXTILES * sizeof (tial));
	inittials ();
}

inittials ()
{
	int i;

	tialcount = 0;
	for (i = 0; i < MAXTILES; i++)
		newtial ();
}

newtial ()
{
	register tial *tp;

	tp = tials + tialcount;
	tp -> what = UNKNOWN;
	tp -> flags = SOCK;
	tp -> ubits = sparebits;
	tp -> ubits.baseaddr = 0L;
	shapetial (tp, &tp -> ubits.bounds, FACEDOWN, SMALL);
	offsetrect (&tp -> ubits.bounds, 
		340 + 14 * (tialcount % 10) + random () % 2,
		90 + 14 * (tialcount / 10) + random () % 2);
	tialcount++;
}

sorttials (tlist, n) tial *tlist[]; register int n;
{
	register tial *temp, **tp;
	register int i;

	for (i = 1; i < n; i++) {
		tp = tlist + i;
		temp = *tp;
		while (tp > tlist  &&
			(temp -> ubits.bounds.a.left < tp[-1] -> ubits.bounds.a.left
		  || temp -> ubits.bounds.a.top < tp[-1] -> ubits.bounds.a.top)) {
			tp[0] = tp[-1];
			--tp;
		}
		*tp = temp;
	}
}		

shapetial (t, r, angle, size) register tial *t; rect *r; register char angle, size;
{
	shaperect (angle, size, r, r);
	t -> shape.angle = angle;
	t -> shape.size = size;
}

#define COSUNIT		1024

/* tcosine[n] == COSUNIT * cos (n * pi / FACEDOWN), 0 <= n <= EDGEON */
static int tcosine[] = {1024, 998, 923, 801, 638, 444, 228, 0};

shaperect (angle, size, in, out) register char angle, size; register rect *in, *out;
{
	point center1, center2;
	int x, y;

	if (UPSIDEDOWN (angle))
		angle = FACEDOWN - angle;
	x = size * tcosine[angle] / COSUNIT;
	y = size;
	rectcenter (in, &center1);
	setrect (out, 0, 0, x, y);
	rectcenter (out, &center2);
	subpt (&center2, &center1);
	offsetrect (out, center1.a.h, center1.a.v);
}

char stepto (from, to, by) register char from, to, by;
{
	if (from < to) {
		from += by;
		if (from > to)
			from = to;
	}
	else if (from > to) {
		from -= by;
		if (from < to)
			from = to;
	}
	return from;
}

steptialshape (t, r) register tial *t; register rect *r;
{
	register char angle, size;

	angle = t -> shape.angle;
	size = t -> shape.size;
	angle = stepto (angle, goalshape.angle, TURNSTEP);
	size = stepto (size, goalshape.size, SIZESTEP);
	shapetial (t, r, angle, size);
}

atgoalshape (t) register tial *t;
{
	return t -> shape.angle == goalshape.angle &&
		t -> shape.size == goalshape.size;
}

finishanim (t) register tial *t;
{
	point p;

	while (!atgoalshape (t))
		movetial (t, &p, &p);
	freebitmap (&t -> ubits);
}

numbertial (n, isnumbered) register int n; int isnumbered;
{
	rect r, nr;
	register int num;
	static long numberset = EMPTY_SET;

	if (n == BLANK)
		return;
	if ((MEMBER (numberset, n) != 0)  == isnumbered)
		return;
	num = value[n];
	nthtialrect (n, &r);
	r.a.right -= 2;
	r.a.left = r.a.right - 6;
	r.a.bottom -= 2;
	r.a.top = r.a.bottom - 6;
	setrect (&nr, num * 6 - 5, 0, num * 6 + 1, 6);
	copybits (numpix, tialpix, &nr, &r, srcxor, 0L);
	FLIP_SET (numberset, n);
}

nthtialrect (n, r) register int n; register rect *r;
{
	*r = tialrect;
	r -> a.right *= n;
	r -> a.left = r -> a.right - T;
}

refreshtial (t) register tial *t;
{
	qdptr save;

	pushmain ();
	save = t -> ubits.baseaddr;
	t -> ubits.baseaddr = 0L;
	drawtial (t, &mainwindow -> portbits);
	t -> ubits.baseaddr = save;
	popport ();
}

drawtials (screen) register bitmap *screen;
{
	register int i;
	register tial *t;

	for (i = tialcount, t = tials; i; --i, t++)
	    if (!(t -> flags & FIXED))
			drawtial (t, screen);
}

drawtial (tp, screen) register tial *tp; register bitmap *screen;
{
	rect r;

	tilerect (&r, UPSIDEDOWN (tp -> shape.angle) ? BLANK : tp -> what);
	if (tp -> ubits.baseaddr)
		copybits (screen, &(tp -> ubits), &(tp -> ubits.bounds),
			&(tp -> ubits.bounds), srccopy, mainwindow -> visrgn);
	copybits (tialpix, screen, &r, &(tp -> ubits.bounds), 
		(tp -> flags & HILITE) ? notsrccopy : srccopy, 0L);
}

undrawtial (tp, screen) register tial *tp; bitmap *screen;
{
	if (!tp -> ubits.baseaddr)
		whatsunder (tp);
	copybits (&(tp -> ubits), screen,
		&(tp -> ubits.bounds), &(tp -> ubits.bounds), srccopy, 0L);
}

movetial (tp, startpt, endpt) register tial *tp; register point *startpt, *endpt;
{
	point delta;
	rect newrect;

	newrect = tp -> ubits.bounds;
	delta = *endpt;
	subpt (startpt, &delta);
	offsetrect (&newrect, delta.a.h, delta.a.v);
	if (!atgoalshape (tp))
		steptialshape (tp, &newrect);
	movetorect (tp, &newrect);
}

movetorect (tp, nr) register tial *tp; register rect *nr;
{
	rect intersection;

	if (sectrect (nr, &(tp -> ubits.bounds), &intersection)) {
		unionrect (nr, &(tp -> ubits.bounds), &(workbits.bounds));
		copybits (&(mainwindow -> portbits), &workbits,
			&workbits.bounds, &workbits.bounds, srccopy, 
			mainwindow -> visrgn);
		undrawtial (tp, &workbits);
		tp -> ubits.bounds = *nr;
		drawtial (tp, &workbits);
		copybits (&workbits, &(mainwindow -> portbits),
			&workbits.bounds, &workbits.bounds, srccopy, 0L);
	}
	else {
		tial oldtial;
		oldtial = *tp ;
		tp -> ubits.bounds = *nr;
		tp -> ubits.baseaddr = sparebits.baseaddr;
		drawtial (tp, &mainwindow -> portbits);
		undrawtial (&oldtial, &mainwindow -> portbits);
		sparebits.baseaddr = oldtial.ubits.baseaddr;
	}
}

ptintial (p, tp) point *p; tial *tp;
{
	return ptinrect (p, &tp -> ubits.bounds);
}

tial *findtial (p) register point *p;
{
	register int i;
	register tial *t;

	for (i = tialcount, t = tials; i; --i, t++)
		if (ptintial (p, t))
			return t;

	return 0L;
}

tial *randomtial (prop) register char prop;
{
	register int i, count;
	register tial *t;

	for (i = tialcount, count = 0, t = tials; i; --i, t++)
		if (t -> flags & prop)
			count++;
	if (!count)
		return 0L;
    for (i = randint (count) + 1, t = tials;; t++)
		if (t -> flags & prop && --i == 0)
			return t;
	sysbeep (15);
}

olapshape (t, where, angle, size) tial *t; rect *where; char angle, size;
{
	rect r;

	shaperect (angle, size, where, &r);
	return olap (t, &r);
}

overlap (th) register tial *th;
{
	rect *r = &th -> ubits.bounds;
	return olap (th, r);
}

olap (th, r) register tial *th; register rect *r;
{
	register int i;
	rect ir;

	for (i = 0; i < tialcount; i++)
		if (tials + i != th && sectrect (r, &tials[i].ubits.bounds, &ir))
				return i + 1;
	return 0;
}

smoothmove (tp, r) register tial *tp; rect *r;
{
	point tcenter, rcenter;

	rectcenter (&tp -> ubits.bounds, &tcenter);
	rectcenter (r, &rcenter);
	smoothanimate (tp, &tcenter, &rcenter);
}

smoothanimate (tp, start, end) register tial *tp; register point *start, *end;
{
	animate (tp, start, end, 10);
}

animate (tp, start, end, iter) register tial *tp; register point *start, *end; register int iter;
{
	point where;
	
	if (iter > 0) {
		where = *end;
		subpt (start, &where);
		where.a.h /= iter;
		where.a.v /= iter;
		addpt (start, &where);
		if (!equalpt (start, &where))
			movetial (tp, start, &where);
		animate (tp, &where, end, iter - 1);
	}
}

tialpinzone (tp, p, r) register tial *tp; point *p; register rect *r;
{
	rect normal;

	shaperect (FACEUP, LARGE, &tp -> ubits.bounds, &normal);
	*r = mainwindow -> portrect;
	addpt (p, &r -> b.topleft);
	subpt (&normal.b.topleft, &r -> b.topleft);
	addpt (p, &r -> b.botright);
	subpt (&normal.b.botright, &r -> b.botright);
}
