#include "bitmapimage/BitmapImageDiff.h"
#include "unittest/TestSuite.h"

static void testBasicDiff(void) {
	uint8_t pixels1[] = {
		0x00, 0x01, 0x02,
		0x03, 0x04, 0x05,
		0x06, 0x07, 0x08
	};
	uint8_t pixels2[] = {
		0x00, 0x01, 0x02,
		0x03, 0xFF, 0x05,
		0x06, 0x07, 0x08
	};
	BitmapImage * image1 = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_GRAY_8, 3, 3, pixels1, false);
	BitmapImage * image2 = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_GRAY_8, 3, 3, pixels2, false);
	BitmapImageDiff * diff = BitmapImageDiff_create(image2, image1);
	TestCase_assertPointerNonNULL(diff);
	TestCase_assertUIntEqual(diff->deltaMinX, 1);
	TestCase_assertUIntEqual(diff->deltaMaxX, 2);
	TestCase_assertUIntEqual(diff->deltaMinY, 1);
	TestCase_assertUIntEqual(diff->deltaMaxY, 2);
	TestCase_assertUIntEqual(diff->xorWidth, 0);
	TestCase_assertUIntEqual(diff->xorHeight, 0);
	TestCase_assertUIntEqual(diff->xorPixelFormat, 0);
	TestCase_assertPointerNULL(diff->oldPixels);
	TestCase_assertPointerNULL(diff->newPixels);
	TestCase_assertPointerNonNULL(diff->xorPixels);
	
	BitmapImage * targetImage = BitmapImage_createWithPixels(BITMAP_PIXEL_FORMAT_GRAY_8, 3, 3, pixels1);
	BitmapImageDiff_apply(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 3);
	TestCase_assertUIntEqual(targetImage->height, 3);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8);
	TestCase_assertBytesEqual(targetImage->pixels, pixels2, sizeof(pixels2));
	
	BitmapImageDiff_revert(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 3);
	TestCase_assertUIntEqual(targetImage->height, 3);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8);
	TestCase_assertBytesEqual(targetImage->pixels, pixels1, sizeof(pixels1));
	
	pixels2[0] = 0xFF;
	pixels2[8] = 0x7F;
	BitmapImageDiff_dispose(diff);
	diff = BitmapImageDiff_create(image2, image1);
	TestCase_assertPointerNonNULL(diff);
	TestCase_assertUIntEqual(diff->deltaMinX, 0);
	TestCase_assertUIntEqual(diff->deltaMaxX, 3);
	TestCase_assertUIntEqual(diff->deltaMinY, 0);
	TestCase_assertUIntEqual(diff->deltaMaxY, 3);
	TestCase_assertUIntEqual(diff->xorWidth, 0);
	TestCase_assertUIntEqual(diff->xorHeight, 0);
	TestCase_assertUIntEqual(diff->xorPixelFormat, 0);
	TestCase_assertPointerNULL(diff->oldPixels);
	TestCase_assertPointerNULL(diff->newPixels);
	TestCase_assertPointerNonNULL(diff->xorPixels);
	
	BitmapImageDiff_apply(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 3);
	TestCase_assertUIntEqual(targetImage->height, 3);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8);
	TestCase_assertBytesEqual(targetImage->pixels, pixels2, sizeof(pixels2));
	
	BitmapImageDiff_revert(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 3);
	TestCase_assertUIntEqual(targetImage->height, 3);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8);
	TestCase_assertBytesEqual(targetImage->pixels, pixels1, sizeof(pixels1));
	BitmapImage_dispose(targetImage);
	
	uint8_t pixels3[] = {
		0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
		0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
		0x10,0x10, 0x10,0x10, 0x10,0x10, 0x10,0x10,
		0x10,0x10, 0x10,0x10, 0x10,0x10, 0x10,0x10
	};
	uint8_t pixels4[] = {
		0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
		0x00,0x00, 0x0F,0x00, 0x00,0x00, 0x00,0x00,
		0x10,0x10, 0x10,0x10, 0x10,0x10, 0x10,0x1F,
		0x10,0x1F, 0x10,0x10, 0x10,0x10, 0x10,0x10
	};
	BitmapImage * image3 = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_GRAYALPHA_88, 4, 4, pixels3, false);
	BitmapImage * image4 = BitmapImage_createWithPixelsNoCopy(BITMAP_PIXEL_FORMAT_GRAYALPHA_88, 4, 4, pixels4, false);
	
	BitmapImageDiff_dispose(diff);
	diff = BitmapImageDiff_create(image4, image3);
	TestCase_assertPointerNonNULL(diff);
	TestCase_assertUIntEqual(diff->deltaMinX, 0);
	TestCase_assertUIntEqual(diff->deltaMaxX, 4);
	TestCase_assertUIntEqual(diff->deltaMinY, 1);
	TestCase_assertUIntEqual(diff->deltaMaxY, 4);
	TestCase_assertUIntEqual(diff->xorWidth, 0);
	TestCase_assertUIntEqual(diff->xorHeight, 0);
	TestCase_assertUIntEqual(diff->xorPixelFormat, 0);
	TestCase_assertPointerNULL(diff->oldPixels);
	TestCase_assertPointerNULL(diff->newPixels);
	TestCase_assertPointerNonNULL(diff->xorPixels);
	
	targetImage = BitmapImage_createWithPixels(BITMAP_PIXEL_FORMAT_GRAYALPHA_88, 4, 4, pixels3);
	BitmapImageDiff_apply(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 4);
	TestCase_assertUIntEqual(targetImage->height, 4);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertBytesEqual(targetImage->pixels, pixels4, sizeof(pixels4));
	
	BitmapImageDiff_revert(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 4);
	TestCase_assertUIntEqual(targetImage->height, 4);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertBytesEqual(targetImage->pixels, pixels3, sizeof(pixels3));
	
	BitmapImageDiff_dispose(diff);
	diff = BitmapImageDiff_create(image1, image3);
	TestCase_assertPointerNonNULL(diff);
	TestCase_assertUIntEqual(diff->xorWidth, 3 ^ 4);
	TestCase_assertUIntEqual(diff->xorHeight, 3 ^ 4);
	TestCase_assertUIntEqual(diff->xorPixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8 ^ BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertPointerNonNULL(diff->oldPixels);
	TestCase_assertPointerNonNULL(diff->newPixels);
	TestCase_assertPointerNULL(diff->xorPixels);
	
	BitmapImageDiff_apply(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 3);
	TestCase_assertUIntEqual(targetImage->height, 3);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAY_8);
	TestCase_assertBytesEqual(targetImage->pixels, pixels1, sizeof(pixels1));
	
	BitmapImageDiff_revert(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 4);
	TestCase_assertUIntEqual(targetImage->height, 4);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertBytesEqual(targetImage->pixels, pixels3, sizeof(pixels3));
	
	BitmapImageDiff_dispose(diff);
	diff = BitmapImageDiff_create(image3, image3);
	TestCase_assertPointerNonNULL(diff);
	TestCase_assertUIntEqual(diff->xorWidth, 0);
	TestCase_assertUIntEqual(diff->xorHeight, 0);
	TestCase_assertUIntEqual(diff->xorPixelFormat, 0);
	TestCase_assertPointerNULL(diff->oldPixels);
	TestCase_assertPointerNULL(diff->newPixels);
	TestCase_assertPointerNULL(diff->xorPixels);
	
	BitmapImageDiff_apply(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 4);
	TestCase_assertUIntEqual(targetImage->height, 4);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertBytesEqual(targetImage->pixels, pixels3, sizeof(pixels3));
	
	BitmapImageDiff_revert(diff, targetImage);
	TestCase_assertUIntEqual(targetImage->width, 4);
	TestCase_assertUIntEqual(targetImage->height, 4);
	TestCase_assertUIntEqual(targetImage->pixelFormat, BITMAP_PIXEL_FORMAT_GRAYALPHA_88);
	TestCase_assertBytesEqual(targetImage->pixels, pixels3, sizeof(pixels3));
	
	BitmapImageDiff_dispose(diff);
	BitmapImage_dispose(targetImage);
	BitmapImage_dispose(image1);
	BitmapImage_dispose(image2);
	BitmapImage_dispose(image3);
	BitmapImage_dispose(image4);
}

TEST_SUITE(BitmapImageDiffTest,
           testBasicDiff)
