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

#define assertColor4ubEqual(value, expected_red, expected_green, expected_blue, expected_alpha) \
	TestCase_assert(value.red == expected_red && value.green == expected_green && value.blue == expected_blue && value.alpha == expected_alpha, "Expected %02X %02X %02X %02X but got %02X %02X %02X %02X", expected_red, expected_green, expected_blue, expected_alpha, value.red, value.green, value.blue, value.alpha)

static void testCompositeColor4ub(void) {
	Color4ub result = compositeColor4ub(COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF), COLOR4ub(0x00, 0x00, 0x00, 0x00));
	assertColor4ubEqual(result, 0xFF, 0xFF, 0xFF, 0xFF);
	result = compositeColor4ub(COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF), COLOR4ub(0x7F, 0x7F, 0x7F, 0x7F));
	assertColor4ubEqual(result, 0xFF, 0xFF, 0xFF, 0xFF);
	result = compositeColor4ub(COLOR4ub(0x7F, 0x7F, 0x7F, 0x7F), COLOR4ub(0x00, 0x00, 0x00, 0x00));
	assertColor4ubEqual(result, 0x7F, 0x7F, 0x7F, 0x7F);
	result = compositeColor4ub(COLOR4ub(0x7F, 0x7F, 0x7F, 0x7F), COLOR4ub(0xFF, 0xFF, 0xFF, 0x00));
	assertColor4ubEqual(result, 0x7F, 0x7F, 0x7F, 0x7F);
	result = compositeColor4ub(COLOR4ub(0x7F, 0x7F, 0x7F, 0x7F), COLOR4ub(0x00, 0x00, 0x00, 0xFF));
	assertColor4ubEqual(result, 0x3F, 0x3F, 0x3F, 0xFF);
	result = compositeColor4ub(COLOR4ub(0x7F, 0x7F, 0x7F, 0x7F), COLOR4ub(0xFF, 0xFF, 0xFF, 0xFF));
	assertColor4ubEqual(result, 0xBF, 0xBF, 0xBF, 0xFF);
}

static void testOverwriteImageWithSelection(void) {
	Selection * selection = Selection_create(1, 1, VECTOR2i_ZERO);
	BitmapImage * fromImage = BitmapImage_create(BITMAP_PIXEL_FORMAT_RGBA_8888, 1, 1);
	BitmapImage * toImage = BitmapImage_create(BITMAP_PIXEL_FORMAT_RGBA_8888, 1, 1);
	selection->cells[0] = 0xFF;
	BitmapImage_clear(toImage, 0x00000000);
	BitmapImage_clear(fromImage, 0x000000FF);
	overwriteImageWithSelection(toImage, fromImage, VECTOR2i_ZERO, selection);
	Color4ub pixel = COLOR4ub(toImage->pixels[0], toImage->pixels[1], toImage->pixels[2], toImage->pixels[3]);
	assertColor4ubEqual(pixel, 0x00, 0x00, 0x00, 0xFF);
	
	BitmapImage_clear(toImage, 0x10203040);
	BitmapImage_clear(fromImage, 0x20406080);
	overwriteImageWithSelection(toImage, fromImage, VECTOR2i_ZERO, selection);
	pixel = COLOR4ub(toImage->pixels[0], toImage->pixels[1], toImage->pixels[2], toImage->pixels[3]);
	assertColor4ubEqual(pixel, 0x20, 0x40, 0x60, 0x80);
	
	selection->cells[0] = 0x7F;
	BitmapImage_clear(toImage, 0x10203040);
	BitmapImage_clear(fromImage, 0x20406080);
	overwriteImageWithSelection(toImage, fromImage, VECTOR2i_ZERO, selection);
	pixel = COLOR4ub(toImage->pixels[0], toImage->pixels[1], toImage->pixels[2], toImage->pixels[3]);
	assertColor4ubEqual(pixel, 0x18, 0x30, 0x48, 0x60);
	
	selection->cells[0] = 0x3F;
	BitmapImage_clear(toImage, 0x10203040);
	BitmapImage_clear(fromImage, 0x20406080);
	overwriteImageWithSelection(toImage, fromImage, VECTOR2i_ZERO, selection);
	pixel = COLOR4ub(toImage->pixels[0], toImage->pixels[1], toImage->pixels[2], toImage->pixels[3]);
	assertColor4ubEqual(pixel, 0x14, 0x28, 0x3C, 0x50);
	
	Selection_dispose(selection);
	BitmapImage_dispose(fromImage);
	BitmapImage_dispose(toImage);
}

static void testIsDataEqual(void) {
	DataHashTable * hashTable1 = hashCreate();
	DataHashTable * hashTable2 = hashCreate();
	TestCase_assertBoolTrue(isDataHashTableEqual(hashTable1, hashTable2));
	hashSet(hashTable1, "a", valueCreateBoolean(false));
	TestCase_assertBoolFalse(isDataHashTableEqual(hashTable1, hashTable2));
	hashSet(hashTable2, "a", valueCreateBoolean(false));
	TestCase_assertBoolTrue(isDataHashTableEqual(hashTable1, hashTable2));
	
	DataArray * array1 = arrayCreate();
	DataArray * array2 = arrayCreate();
	TestCase_assertBoolTrue(isDataArrayEqual(array1, array2));
	arrayAppend(array1, valueCreateInt8(1));
	TestCase_assertBoolFalse(isDataArrayEqual(array1, array2));
	arrayAppend(array2, valueCreateInt8(2));
	TestCase_assertBoolFalse(isDataArrayEqual(array1, array2));
	arrayReplace(array2, 0, valueCreateInt8(1));
	TestCase_assertBoolTrue(isDataArrayEqual(array1, array2));
	
	DataAssociativeArray * associativeArray1 = associativeArrayCreate();
	DataAssociativeArray * associativeArray2 = associativeArrayCreate();
	TestCase_assertBoolTrue(isDataAssociativeArrayEqual(associativeArray1, associativeArray2));
	associativeArrayAppend(associativeArray1, "a", valueCreateHashTable(hashTable1, false, false));
	TestCase_assertBoolFalse(isDataAssociativeArrayEqual(associativeArray1, associativeArray2));
	associativeArrayAppend(associativeArray2, "a", valueCreateHashTable(hashTable2, false, false));
	TestCase_assertBoolTrue(isDataAssociativeArrayEqual(associativeArray1, associativeArray2));
	hashSet(hashTable1, "a", valueCreateBoolean(true));
	TestCase_assertBoolFalse(isDataAssociativeArrayEqual(associativeArray1, associativeArray2));
	
	hashDispose(hashTable1);
	hashDispose(hashTable2);
	arrayDispose(array1);
	arrayDispose(array2);
	associativeArrayDispose(associativeArray1);
	associativeArrayDispose(associativeArray2);
}

static void testGetZoomLevelForSizes(void) {
	float result = getZoomLevelForSizes(VECTOR2f(1, 1), VECTOR2u(1, 1));
	TestCase_assertFloatEqual(result, 1.0f);
	result = getZoomLevelForSizes(VECTOR2f(40, 30), VECTOR2u(30, 30));
	TestCase_assertFloatEqual(result, 1.0f);
	result = getZoomLevelForSizes(VECTOR2f(30, 40), VECTOR2u(30, 30));
	TestCase_assertFloatEqual(result, 1.0f);
	result = getZoomLevelForSizes(VECTOR2f(40, 30), VECTOR2u(20, 15));
	TestCase_assertFloatEqual(result, 2.0f);
	result = getZoomLevelForSizes(VECTOR2f(40, 30), VECTOR2u(19, 14));
	TestCase_assertFloatEqual(result, 2.0f);
	result = getZoomLevelForSizes(VECTOR2f(40, 30), VECTOR2u(30, 40));
	TestCase_assertFloatEqual(result, 0.5f);
	result = getZoomLevelForSizes(VECTOR2f(30, 30), VECTOR2u(10, 10));
	TestCase_assertFloatEqual(result, 3.0f);
	result = getZoomLevelForSizes(VECTOR2f(10, 10), VECTOR2u(30, 30));
	TestCase_assertFloatEqual(result, 0.25f);
	result = getZoomLevelForSizes(VECTOR2f(0, 0), VECTOR2u(0, 0));
	TestCase_assertFloatEqual(result, 1.0f);
}

TEST_SUITE(UtilitiesTest,
           testCompositeColor4ub,
           testOverwriteImageWithSelection,
           testIsDataEqual,
           testGetZoomLevelForSizes)
