/*
*Copyright(c)2019, Jeffrey Lee
*Allrightsreserved.
*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met: 
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "dirtyrect.h"

#define TEST_WIDTH 32 // Must be <= 32
#define TEST_HEIGHT 32
#define TEST_MAX_RECT 16

typedef struct {
	dirtyrect_buffer dirty;
	area areas[TEST_MAX_RECT];
	uint32_t test_area[TEST_HEIGHT];
} test_state;

static int randn(int n)
{
	int i = rand() / (RAND_MAX / n);
	return (i >= n ? n-1 : i);
}

static void do_test(test_state *t)
{
	dirtyrect_init(&t->dirty);
	int rects = randn(TEST_MAX_RECT+1);
	if (rects < 2)
	{
		rects = 2;
	}
	for(int i=0;i<rects;i++)
	{
		int x0 = randn(TEST_WIDTH);
		int x1 = randn(TEST_WIDTH-x0)+x0+1;
		int y0 = randn(TEST_HEIGHT);
		int y1 = randn(TEST_HEIGHT-y0)+y0+1;
		set_area(&t->areas[i],x0,y0,x1-x0,y1-y0);
		dirtyrect_add(&t->dirty,&t->areas[i]);
		for(int y=y0;y<y1;y++)
		{
			t->test_area[y] |= (1<<x1)-(1<<x0);
		}
	}
	area a;
	while(true)
	{
		dirtyrect_next(&t->dirty,&a);
		if (area_is_empty(&a))
		{
			break;
		}
		for(int y=0;y<a.h;y++)
		{
			t->test_area[y+a.y] &= ~(((1<<a.w)-1)<<a.x);
		}
	}
	bool fail = false;
	for(int i=0;i<TEST_HEIGHT;i++)
	{
		if (t->test_area[i])
		{
			fail = true;
			break;
		}
	}
	if (!fail)
	{
		return;
	}
	printf("FAIL (%d)\n",rects);
	for(int i=0;i<rects;i++)
	{
		printf("%d,%d,%d,%d,\n",t->areas[i].x,t->areas[i].y,t->areas[i].w,t->areas[i].h);
	}
	for(int i=0;i<TEST_HEIGHT;i++)
	{
		printf("%08x\n",t->test_area[i]);
	}
}

int main(int argc,char **argv)
{
	int i=0;
	test_state t;
	memset(&t,0,sizeof(t));
	while(true)
	{
		do_test(&t);
		i++;
		if (!(i & 1023))
		{
			printf("%d\n",i);
		}
	}
	return 0;
}
