#define	ARCH_VERBOSE

#include <../arch/arch.h>

vboolean	V_CALL
archWinClearRect(arch_window_p aw,u32_t left,u32_t top,u32_t right,u32_t bottom,
	colorquad_t color)
{
	BOOL result;
	HBRUSH old, brush;
	/* fixme: should we hash brushes ??? */
	brush = CreateSolidBrush(RGB(color.r,color.g,color.b));
	old = SelectObject(aw->dc,brush);
	result = PatBlt(aw->dc,left,top,right-left+1,bottom-top+1,PATCOPY);
	DeleteObject(SelectObject(aw->dc,old));
	return (result) ? true : false;
}

vboolean	V_CALL
archWinClear(arch_window_p aw,colorquad_t color)
{
	return archWinClearRect(aw,0,0,aw->width-1,aw->height-1,color);
}

vboolean	V_CALL
archWinDrawPixelsBGRA(arch_window_p aw,
	u32_t dst_left,u32_t dst_top, /* upper-left corner of destination rectangle */
	
	u32_t src_left,u32_t src_top, /* upper-left corner of source rectangle */
	u32_t src_right,u32_t src_bottom, /* lower-right corner of source rectangle */

	u32_t src_block_width,u32_t src_block_height, /* size of source image */
	u8_t bgra[])
{
	s32_t num_rows, num_cols;
	BITMAPINFOHEADER head;
	/* Clip lower-right corner of source rectangle */
	if(src_right >= src_block_width)
		src_right = src_block_width - 1;
	if(src_bottom >= src_block_height)
		src_bottom = src_block_height - 1;
	num_cols = (s32_t)src_right - (s32_t)src_left + 1;
	num_rows = (s32_t)src_bottom - (s32_t)src_top + 1;
	/* Check region is empty */
	if(num_cols <= 0  || num_rows <= 0)
		return false;
	/* Clip for destination area */
	if((dst_left + num_cols) > aw->width)
		num_cols = aw->width - dst_left;
	if((dst_top + num_rows) > aw->height)
		num_rows = aw->height - dst_top;
	/* Check region is empty */
	if(num_cols <= 0  || num_rows <= 0)
		return false;
	/* Setup header for bit transfer */
	memZero(&head,sizeof(head));
	head.biSize = sizeof(head);
	head.biWidth = src_block_width;
	head.biHeight = -src_block_height; /* top-down bitmap */
	head.biPlanes = 1;
	head.biBitCount = 32;
	head.biCompression = BI_RGB;
    
    /* Twist the logic to reflect twisted logic of SetDIBitsToDevice() */
    src_bottom = src_top + num_rows - 1;
	src_top = src_block_height - src_bottom - 1;

	return  SetDIBitsToDevice(aw->dc,
		(int)dst_left, (int)dst_top,
		(DWORD)num_cols, (DWORD)num_rows,
		(int)src_left, (int)src_top,
		(UINT)0, (UINT)src_block_height,
		bgra,
		(LPBITMAPINFO)&head,DIB_RGB_COLORS) ? true : false;
}

void bgra2rgba(u32_t src_width,u32_t src_height,u8_t buf[])
{
	u32_t len = src_width * src_height;
	/*
	__asm
	{
		mov edx, buf
		mov ecx, len
		dec ecx
l0:
		mov eax, [edx+4*ecx]
		bswap eax
		shr eax, 8
		mov [edx+4*ecx], eax
		dec ecx
		jnz l0
	} 
	*/
	u8_p ptr = buf, endptr = ptr + 4 * len;
	u8_t tmp;
	while(ptr < endptr)
	{
		tmp = ptr[0];
		ptr[0] = ptr[2];
		ptr[2] = tmp;
		ptr += 4;
	}
}

void V_CALL
archWinPostRedisplay(arch_window_p aw,u32_t left,u32_t top,u32_t right,u32_t bottom)
{
	RECT rc;
	rc.left = left;
	rc.top = top;
	rc.right = right;
	rc.bottom = bottom;
	InvalidateRect(aw->wnd,&rc,FALSE);
	UpdateWindow(aw->wnd);
}

void enum_children(arch_window_p aw)
{
	TREE_ITERATOR;
   	printf("window '%s'\n",aw->title);
   	TREE_FOR_EACH_CHILD(aw)
	{
    	arch_window_p ptr = TREE_NODE(arch_window_t);
    	enum_children(ptr);
    }
}

void enum_from_root(arch_window_p any_child)
{
	while(any_child->parent)
		any_child = any_child->parent;
	enum_children(any_child);
}

int main_(void)
{
	arch_window_p aw, ch;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	aw = archWinOpen(NULL,"hello",NULL,10,20,512,384,true,true);
	ch = archWinOpen(aw,"hello-ch1",NULL,10,20,512,384,true,true);
	enum_from_root(ch);
	archWinClose(ch);
	puts("-------------");
	enum_from_root(aw);
	archWinClose(aw);
	memPrintStats();
	return 0;
}

int main(void)
{
	u32_t w, h;
	u8_p pixels;
	arch_window_p aw, ch;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);

	aw = archWinOpen(NULL,"hello",NULL,10,20,512,384,true,true);
	archWinShow(aw,true);
	ch = archWinOpen(aw,"hello-child",NULL,10,20,30,40,true,true);
	archWinShow(ch,true);
	
	/* {
		int i=0;
		vidmode_p vm;
		while(vm = archWinGetVideoMode(aw,i))
		{
			if(vm->width == 800 && vm->height == 600 &&
				vm->bpp == 32 && vm->refresh == 60)
				break;
			i++;
		}
		if(archWinGetVideoMode(aw,i))
			archWinSetVideoMode(aw,i,NULL);
	} */

	pixels = jpgLoad("../../../media/env/alien3ft.jpg",&w,&h);
	V_ASSERT(pixels);

	bgra2rgba(w,h,pixels);
#define dump(msg,name) \
	printf("%s [%3.2f] (%i,%i,%i,%i)\n",#name,MSG_TIME(&msg),(msg).code[0],(msg).code[1],(msg).code[2],(msg).code[3])
		
	{
		colorquad_t red = {255,0,0,255};
		colorquad_t black = {0,0,0,255};
		vboolean need_redraw;
		u32_t dleft = 0, dtop = 0;
		u32_t sleft = 0, stop = 0;
		u32_t sright, sbottom;
		static flip = 0;
		ui_message_t msg;
		sright = w-1;
		sbottom = h-1;
		
		for(;;)
		{
			archWinNextMessage(aw,&msg);
			if(MSG_EVENT(&msg) == ui_event_close)
				break;
			switch(MSG_EVENT(&msg))
			{
				case ui_event_redraw:
					archWinClearRect(aw,
						MSG_DRAW_LEFT(&msg),
						MSG_DRAW_TOP(&msg),
						MSG_DRAW_RIGHT(&msg),
						MSG_DRAW_BOTTOM(&msg),
						(++flip & 1) ? red : black);
					dump(msg,ui_event_redraw);
					archWinDrawPixelsBGRA(aw,dleft,dtop,sleft,stop,
						sright,sbottom,w,h,pixels);
					break;
				case ui_event_activate:
					dump(msg,ui_event_activate);
					break;
				case ui_event_move:
					dump(msg,ui_move);
					{
						colorquad_t c = {0,0,0,0};
						c.r = (u8_t)rand();
						c.g = (u8_t)rand();
						c.b = (u8_t)rand();
						archWinClear(aw,c);
					}
					break;
				case ui_event_size:
					dump(msg,ui_event_size);
					break;
				case ui_event_key_down:
					dump(msg,ui_event_key_down);
					need_redraw = true;
					switch(MSG_KEY_CODE(&msg))
					{
						case key_left: if(dleft > 0) dleft--; break;
						case key_right: if(dleft < (aw->width-(sright-sleft))) dleft++; break;
						case key_up: if(dtop > 0) dtop--; break;
						case key_down: if(dtop < (aw->height-(sbottom-stop))) dtop++; break;

						case key_delete: if(sleft > 0) sleft--; break;
						case key_pagedown: if(sleft < sright) sleft++; break;

						case key_home: if(stop > 0) stop--; break;
						case key_end: if(stop < sbottom) stop++; break;

						case key_A: if(sright > sleft) sright--; break;
						case key_D: if(sright < w) sright++; break;

						case key_W: if(sbottom > stop) sbottom--; break;
						case key_S: if(sbottom < h) sbottom++; break;
						
						case key_left_mouse:
							archWinCapturePointer(aw,true);

						default:
							need_redraw = false;
							break;
					}
					if(need_redraw)
						archWinPostRedisplay(aw,0,0,aw->width-1,aw->height-1);
					break;
				case ui_event_key_up:
					if(MSG_KEY_CODE(&msg) == key_left_mouse)
						archWinCapturePointer(aw,false);
					dump(msg,ui_event_key_up);
					break;
				case ui_event_mouse_move:
					dump(msg,ui_event_mouse_move);
					break;
			}
		}
	}
	archWinClose(aw);
	memFree(pixels);

	memPrintStats();
	return 0;
}

/*
#if 0
_src_width$ = 8
_src_height$ = 12
_buf$ = 16
_bgra2rgba PROC
	mov	ecx, DWORD PTR _src_width$[esp-4]
	imul	ecx, DWORD PTR _src_height$[esp-4]
	mov	eax, DWORD PTR _buf$[esp-4]
	add	ecx, eax
	cmp	eax, ecx
	jae	SHORT $L29579
	push	ebx
$L29578:
	mov	dl, BYTE PTR [eax]
	mov	bl, BYTE PTR [eax+2]
	; fixme - swap next two instuctions ?
	mov	BYTE PTR [eax], bl
	mov	BYTE PTR [eax+2], dl
	add	eax, 4
	cmp	eax, ecx
	jb	SHORT $L29578
	pop	ebx
$L29579:
	ret	0
_bgra2rgba ENDP
#endif


int __main()
{
	u32_t i, tm, w = 1024, h = 1024;
	u8_p pixbuf = (u8_p)memAllocZ(w * h * 4);
	tm = GetTickCount();
	for(i=0;i<100;i++)
		bgra2rgba(w,h,pixbuf);
	tm = GetTickCount() - tm;
	printf("%u ms\n",tm);
	return 0;
}
*/

