#include "tileeditor/ColorPalette.h"
#include "unittest/TestSuite.h"

static void assertColor4ubEqual(Color4ub color, Color4ub expectedColor, unsigned int line) {
	TestCase_assert(color.red == expectedColor.red && color.green == expectedColor.green && color.blue == expectedColor.blue && color.alpha == expectedColor.alpha, "Expected {0x%02X, 0x%02X, 0x%02X, 0x%02X} but got {0x%02X, 0x%02X, 0x%02X, 0x%02X} (line %u)", expectedColor.red, expectedColor.green, expectedColor.blue, expectedColor.alpha, color.red, color.green, color.blue, color.alpha, line);
}

static void testCreate(void) {
	ColorPalette * colorPalette;
	ColorPalette_entry color = {"name", COLOR4ub(0x00, 0x00, 0x00, 0xFF)};
	
	colorPalette = ColorPalette_create(NULL, 1, &color);
	TestCase_assertPointerNonNULL(colorPalette);
	TestCase_assertPointerNULL(colorPalette->name);
	TestCase_assertUIntEqual(colorPalette->colorCount, 1);
	TestCase_assertPointerNonNULL(colorPalette->colors);
	assertColor4ubEqual(colorPalette->colors[0].color, COLOR4ub(0x00, 0x00, 0x00, 0xFF), __LINE__);
	TestCase_assertPointerNonNULL(colorPalette->colors[0].name);
	TestCase_assertPointerUnequal(colorPalette->colors[0].name, color.name);
	TestCase_assertStringEqual(colorPalette->colors[0].name, color.name);
	ColorPalette_dispose(colorPalette);
	
	ColorPalette_entry colors[] = {
		{"color1", COLOR4ub(0x01, 0x02, 0x03, 0xFF)},
		{"color2", COLOR4ub(0x06, 0x05, 0x04, 0xFF)}
	};
	const char * paletteName = "palette";
	colorPalette = ColorPalette_create(paletteName, 2, colors);
	TestCase_assertPointerNonNULL(colorPalette);
	TestCase_assertPointerNonNULL(colorPalette->name);
	TestCase_assertPointerUnequal(colorPalette->name, paletteName);
	TestCase_assertStringEqual(colorPalette->name, paletteName);
	TestCase_assertUIntEqual(colorPalette->colorCount, 2);
	TestCase_assertPointerNonNULL(colorPalette->colors);
	for (unsigned int colorIndex = 0; colorIndex < 2; colorIndex++) {
		assertColor4ubEqual(colorPalette->colors[colorIndex].color, colors[colorIndex].color, __LINE__);
		TestCase_assertPointerNonNULL(colorPalette->colors[colorIndex].name);
		TestCase_assertPointerUnequal(colorPalette->colors[colorIndex].name, colors[colorIndex].name);
		TestCase_assertStringEqual(colorPalette->colors[colorIndex].name, colors[colorIndex].name);
	}
	ColorPalette_dispose(colorPalette);
}

static void testClosestPaletteColor(void) {
	ColorPalette_entry colors1[] = {
		{"black", {0x00, 0x00, 0x00, 0xFF}},
		{"white", {0xFF, 0xFF, 0xFF, 0xFF}}
	};
	ColorPalette * colorPalette = ColorPalette_create(NULL, sizeof(colors1) / sizeof(colors1[0]), colors1);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x00, 0x00, 0x00, 0xFF)), 0);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF)), 1);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0x7F, 0x7F, 0xFF)), 0);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x80, 0x80, 0x80, 0xFF)), 1);
	ColorPalette_dispose(colorPalette);
	
	ColorPalette_entry colors2[] = {
		{"black",       {0x00, 0x00, 0x00, 0xFF}},
		{"white",       {0xFF, 0xFF, 0xFF, 0xFF}},
		{"red",         {0xFF, 0x00, 0x00, 0xFF}},
		{"green",       {0x00, 0xFF, 0x00, 0xFF}},
		{"blue",        {0x00, 0x00, 0xFF, 0xFF}},
		{"dark red",    {0x7F, 0x00, 0x00, 0xFF}},
		{"light green", {0x7F, 0xFF, 0x7F, 0xFF}},
		{"cyan",        {0x00, 0xFF, 0xFF, 0xFF}},
		{"dark gray",   {0x3F, 0x3F, 0x3F, 0xFF}},
		{"gray",        {0x7F, 0x7F, 0x7F, 0xFF}},
		{"light gray",  {0xBF, 0xBF, 0xBF, 0xFF}},
	};
	colorPalette = ColorPalette_create(NULL, sizeof(colors2) / sizeof(colors2[0]), colors2);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x00, 0x00, 0x00, 0xFF)), 0);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF)), 1);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xFF, 0x00, 0x00, 0xFF)), 2);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x00, 0xFF, 0x00, 0xFF)), 3);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x00, 0x00, 0xFF, 0xFF)), 4);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0x00, 0x00, 0xFF)), 5);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0xFF, 0x7F, 0xFF)), 6);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x00, 0xFF, 0xFF, 0xFF)), 7);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x3F, 0x3F, 0x3F, 0xFF)), 8);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0x7F, 0x7F, 0xFF)), 9);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xBF, 0xBF, 0xBF, 0xFF)), 10);
	
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xBF, 0x00, 0x00, 0xFF)), 2);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0xBE, 0x00, 0x00, 0xFF)), 5);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0xBF, 0x7F, 0xFF)), 6);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x7F, 0xBE, 0x7F, 0xFF)), 9);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x1F, 0x20, 0x21, 0xFF)), 8);
	TestCase_assertUIntEqual(ColorPalette_closestPaletteColor(colorPalette, COLOR4ub(0x1B, 0x21, 0x21, 0xFF)), 0);
	ColorPalette_dispose(colorPalette);
}

static void testCreateFromImage(void) {
	unsigned char pixels[] = {0x00,0x00,0x00,0xFF, 0xFF,0xFF,0xFF,0xFF, 0x00,0x00,0x00,0xFF,
	                          0xFF,0x00,0x00,0xFF, 0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0x00,0xFF,
	                          0x00,0xFF,0x00,0x00, 0xFF,0x00,0x00,0xFF, 0x00,0x00,0xFF,0xFF};
	BitmapImage * image = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_RGBA_8888, 3, 3, pixels, false);
	ColorPalette * colorPalette = ColorPalette_createFromImage(image);
	TestCase_assertUIntEqual(colorPalette->colorCount, 6);
	assertColor4ubEqual(colorPalette->colors[0].color, COLOR4ub(0x00, 0x00, 0x00, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[1].color, COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[2].color, COLOR4ub(0xFF, 0x00, 0x00, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[3].color, COLOR4ub(0xFF, 0xFF, 0x00, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[4].color, COLOR4ub(0x00, 0xFF, 0x00, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[5].color, COLOR4ub(0x00, 0x00, 0xFF, 0xFF), __LINE__);
	ColorPalette_dispose(colorPalette);
	BitmapImage_dispose(image);
	
	unsigned char pixels2[] = {0x01,0x02,0x03,0xFF, 0x04,0x05,0x06,0xFF,
	                           0x04,0x05,0x06,0xFF, 0x01,0x02,0x03,0x7F};
	image = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_RGBA_8888, 2, 2, pixels2, false);
	colorPalette = ColorPalette_createFromImage(image);
	TestCase_assertUIntEqual(colorPalette->colorCount, 2);
	assertColor4ubEqual(colorPalette->colors[0].color, COLOR4ub(0x01, 0x02, 0x03, 0xFF), __LINE__);
	assertColor4ubEqual(colorPalette->colors[1].color, COLOR4ub(0x04, 0x05, 0x06, 0xFF), __LINE__);
	ColorPalette_dispose(colorPalette);
	BitmapImage_dispose(image);
}

TEST_SUITE(ColorPaletteTest,
           testCreate,
           testClosestPaletteColor,
           testCreateFromImage)
