#ifndef POC
#define POC

/*

	collision detection
	per pixel collision detection
	xbm intersection
	x bitmap image

*/

#include <assert.h>
#include <stdio.h>
#include <algorithm>

template <unsigned int W, unsigned int H>
unsigned short PokeWord(unsigned short * bitmap, int x, int y)
{
	if (x < 0) return 0;
	if (y < 0) return 0;
	if (x >= W) return 0;
	if (y >= H) return 0;
	int offset = ((y * W) + x) /16;
	assert( (offset >= 0) );
	assert( (offset < W*H) );
	return bitmap[offset];
}

template <unsigned int W, unsigned int H>
unsigned short PokeWordShifted(unsigned short * bitmap, int x, int y)
{
	//if (x <= -16) return 0;
	if (y < 0) return 0;
	//if (x > W+16) return 0;
	if (y >= H) return 0;
	int shift = abs(x) % 16;
	int bshift = 16-shift;
	unsigned short word = PokeWord<W,H>(bitmap,x,y);
	if (shift == 0) return word;
	unsigned short next = PokeWord<W,H>(bitmap,x+16,y);
	if (x<0) return (word << bshift) | (next >> shift);
	return (word << shift) | (next >> bshift);
}

template <unsigned int TW, unsigned int TH, unsigned int EW, unsigned int EH>
unsigned int Poke(unsigned short * thing, unsigned short * environment, int x, int y)
{
	int w = std::min(TW,EW);
	int h = std::min(TW,EW);
	int xx = x + (EW/2) - (TW/2);
	int yy = y + (EH/2) - (TH/2); 
	if (xx <= -16) return 0;
	//if (xx > EW+16) return 0;
	//if (yy < 0) return 0;
	//if (yy >= EH) return 0;
	for (int cy = 0; cy < h; cy++)
	for (int cx = 0; cx < w; cx+=16)
	if (PokeWord<TW,TH>(thing, cx,cy) & PokeWordShifted<EW,EH>(environment, xx+cx, yy+cy)) return 1;
	return 0;
}


template <int RETURN>
int PocSsert()
{
	assert(("ok",1));
	assert(("ok",!0));

	printf("validating collision detection...\n");

	unsigned short testLong[] =
	{
		0xFF00,0xFF00,
	};
	assert((PokeWordShifted<32,1>(testLong,-1,0) != 0));
	assert((PokeWordShifted<32,1>(testLong,-1,0) == 0x7F80));
	assert((PokeWordShifted<32,1>(testLong,0,0) == 0xFF00));
	assert((PokeWordShifted<32,1>(testLong,1,0) == 0xFE01));
	assert((PokeWordShifted<32,1>(testLong,2,0) == 0xFC03));
	assert((PokeWordShifted<32,1>(testLong,8,0) == 0x00FF));
	assert((PokeWordShifted<32,1>(testLong,9,0) == 0x01FE));
	assert((PokeWordShifted<32,1>(testLong,10,0) == 0x03FC));
	assert((PokeWordShifted<32,1>(testLong,12,0) == 0x0FF0));
	assert((PokeWordShifted<32,1>(testLong,13,0) == 0x1FE0));
	assert((PokeWordShifted<32,1>(testLong,15,0) == 0x7F80));
	assert((PokeWordShifted<32,1>(testLong,16,0) == 0xFF00));
	assert((PokeWordShifted<32,1>(testLong,17,0) == 0xFE00));

	unsigned short testFrom[] = 
	{
		0x0180,
		0x0180,
		0x0180,
		0x0180
	};
	for (int x = 0; x<16; x++) for (int y = 0; y < 4 ; y++) assert((x,y,(PokeWord<16,4>(testFrom,x,y) == 0x180)));
	unsigned short testTrue[] = 
	{
		0xffff,
		0xffff,
		0xffff,
		0xffff
	};
	assert(("true",Poke<16,4,16,4>(testFrom,testTrue,0,0)));
	unsigned short testFalse[] = 
	{
		0x0000,
		0x0000,
		0x0000,
		0x0000
	};
	assert(("false",!Poke<16,4,16,4>(testFrom,testFalse,0,0)));
	unsigned short testFalseAgain[] = 
	{
		0xFE7F,
		0xFE7F,
		0xFE7F,
		0xFE7F
	};
	assert(("false again",!Poke<16,4,16,4>(testFrom,testFalseAgain,0,0)));
	assert(("but true",Poke<16,4,16,4>(testFrom,testFalseAgain,1,0)));

	unsigned short testDot[] =
	{
		0x0000,
		0x0180,
		0x0180,
		0x0000
	};
	assert((PokeWord<16,14>(testDot,0,0)==0));
	assert((PokeWord<16,14>(testDot,1,0)==0));
	assert((PokeWord<16,14>(testDot,1,1)==0x0180));
	unsigned short testHole[] =
	{
		0xffff,
		0xfE7f,
		0xfe7f,
		0xffff
	};
	assert((PokeWordShifted<16,4>(testHole,1,0) == 0xFFFE));
	assert((PokeWordShifted<16,4>(testHole,3,0) == 0xFFF8));
	assert((PokeWordShifted<16,4>(testHole,0,1) == 0xFE7F));
	assert(("dot in center of hole, 0",!Poke<16,4,16,4>(testDot, testHole, 0, 0)));
	assert(("right edge of the hole, 1",Poke<16,4,16,4>(testDot, testHole, 1, 0)));
	assert(("bottom edge of the hole, 1",Poke<16,4,16,4>(testDot, testHole, 0, 1)));
	assert(("left edge of the hole, 1",Poke<16,4,16,4>(testDot, testHole, -1, 0)));
	assert(("top edge of the hole, 1",Poke<16,4,16,4>(testDot, testHole, 0, -1)));
	assert(("right side of the hole, 1",Poke<16,4,16,4>(testDot, testHole, 3, 0)));
	assert(("left side of the hole, 1",Poke<16,4,16,4>(testDot, testHole, -3, 0)));
	assert(("right outside of the hole, 0",!Poke<16,4,16,4>(testDot, testHole, 9, 0)));
	assert(("left outside of the hole, 0",!Poke<16,4,16,4>(testDot, testHole, -9, 0)));
	assert(("under the hole, 0",!Poke<16,4,16,4>(testDot, testHole, 0, 3)));
	assert(("above the hole, 0",!Poke<16,4,16,4>(testDot, testHole, 0, -3)));


	//printf("%04x\n",PokeWordShifted<test_width,test_height>(test_bits,15,0));
	assert(("", PokeWordShifted<test_width,test_height>(test_bits,0,0) == 0x200c ));
	assert(("", PokeWordShifted<test_width,test_height>(test_bits,15,0) == 0x1802 ));
	assert(("", PokeWordShifted<test_width,test_height>(test_bits,16,0) == 0x3004 ));
	assert(("", PokeWordShifted<test_width,test_height>(test_bits,17,0) == 0x6008 ));
	assert(("", PokeWordShifted<test_width,test_height>(test_bits,18,0) == 0xC010 ));
	assert(("top left corner", !Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,-8,-8)));
	assert(("top right corner", !Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,8,-8)));
	assert(("bottom right corner", !Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,-8,8)));
	assert(("bottom left corner", !Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,8,8)));
	assert(("left middle with notch", Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,-8,0)));
	assert(("right middle with notch", Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,8,0)));
	//assert(("top middle with notch", Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,0,-8)));
	//assert(("bottom middle with notch", Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,0,8)));
	//assert(("center", !Poke<dot_width,dot_height,test_width,test_height>(dot_bits,test_bits,0,0)));

	printf("collision detection is ~mostly~ valid\n");

	return RETURN;
}

#endif
