//
// ui-win.c
//
//
//
//-UserX 2002/03/24

#include <assert.h>

#include "misc/compat.h"

#include "ui/ui.h"

#include "ui/ui-win.h"
//todo: remove this dependence on iip/wingui.h (move offending variables into ui/ui-win)
#include "iip/wingui.h"

#include "base/mem.h"
#include "base/str.h"
#include "base/array.h"
#include "base/logger.h"

#include "crypt/random.h"

#include "msgcore/core.h"

/**
@author UserX
@name ui-win
*/
//@{


UIWinWindow blankuiwinwindow = {
	{
		NULL, 
		NULL, 
		(UIFuncUIWindowInit)uiwwInit, 
		(UIFuncUIWindowFree)uiwwFree, 
		(UIFuncUIWindowRun)uiwwRun, 
		(UIFuncUIControlSetState)uiwcSetState, 
		(UIFuncUIControlSetValue)uiwcSetValue,
		(UIFuncUIEntryAdd)uiwwAddControl
	},
	0,
	0,
	NULL,
	UIWIN_INACTIVE,
	0,
	0,
	NULL,
	0,
	0,
	0,
	0,
	0,
	0
};

typedef struct UIWinHWND {
	UIWinWindow *uiww;
	HWND hwnd;
	int visible;
} UIWinHWND;

typedef struct UIWinHWNDArrayHandle {
	int size;
	UIWinHWND *data;
} UIWinHWNDArrayHandle;


#define WINCLASSSTRING "iipuiwin"
WNDCLASSEX *WinClass = NULL;
ATOM WinClassAtom;


UIWinHWNDArrayHandle *uiwha = NULL;

UIWinHWND blankuiwh = {NULL, NULL, 0};



enum ID_ {
	ID_BUTTON_UIGE_OK = 1
};

UIEntry uiwgetentropy[] = {
	{UITYPE_TEXT, 0, "", NULL},
	{UITYPE_TEXT, 0, N_("Please move the mouse and or press random keys."), NULL},
	{UITYPE_TEXT, 0, N_("Click OK once done."), NULL},
	{UITYPE_BUTTONOK, ID_BUTTON_UIGE_OK, N_("OK"), NULL}, //(UIFuncNotifyUIControl2) uiwgeNotify},
	BLANKUIENTRY
};


void uiwhAdd(UIWinWindow *uiww, HWND hwnd) {
	int i;
	if(uiwha == NULL) {
		uiwha = (UIWinHWNDArrayHandle *)arrayMake(sizeof(UIWinHWND), 0, &blankuiwh, NULL, NULL);
	}
	i = uiwha->size;
	arrayInsert((ArrayHandle *)uiwha, i, 1);
	uiwha->data[i].uiww = uiww;
	uiwha->data[i].hwnd = hwnd;
}

void uiwhDelete(UIWinWindow *uiww) {
	int i;
	if(uiwha == NULL) {
		return;
	}
	for(i = 0; i < uiwha->size; i++) {
		if(uiwha->data[i].uiww == uiww) {
			arrayDelete((ArrayHandle *)uiwha, i, 1);
			break;
		}
	}
	if(uiwha->size == 0) {
		arrayFree((ArrayHandle *)uiwha);
		uiwha = NULL;
	}
}

UIWinWindow *uiwhFind(HWND hwnd) {
	int i;
	if(uiwha == NULL) {
		return NULL;
	}
	for(i = 0; i < uiwha->size; i++) {
		if(uiwha->data[i].hwnd == hwnd) {
			return uiwha->data[i].uiww;
		}
	}
	return NULL;
}

void uiwhShow(HWND hwnd) {
	int i;
	if(uiwha == NULL) {
		return;
	}
	for(i = 0; i < uiwha->size; i++) {
		if(uiwha->data[i].hwnd == hwnd) {
			if(uiwha->data[i].visible == 0) {
				ShowWindow(uiwha->data[i].hwnd, SW_SHOW);
				uiwha->data[i].visible = 1;
			}
		}
	}
	return;
}

void uiwhHideOthers(HWND hwnd) {
	int i;
	if(uiwha == NULL) {
		return;
	}
	for(i = 0; i < uiwha->size; i++) {
		if(uiwha->data[i].hwnd != hwnd) {
			ShowWindow(uiwha->data[i].hwnd, SW_HIDE);
			uiwha->data[i].visible = 0;
		}
	}
	return;
}

char *uiwGetClass(void) {

	if(WinClass != NULL) {
		return WINCLASSSTRING;
	}

	WinClass = memAlloc(sizeof(WNDCLASSEX), "UI-Win WinClass", WINCLASSSTRING);
	
	WinClass->cbSize			= sizeof(WNDCLASSEX);
	WinClass->style			= CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;// | CS_OWNDC;
	//WinClass->lpfnWndProc	= uiwwNotify;
	WinClass->lpfnWndProc	= uiwwcProc;
	WinClass->cbClsExtra		= 0;
	WinClass->cbWndExtra		= 0;
	WinClass->hInstance		= hinst;
	WinClass->hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	WinClass->hCursor		= LoadCursor(NULL, IDC_ARROW);
	WinClass->hbrBackground	= (HBRUSH)(COLOR_BTNFACE + 1); //(HBRUSH)GetStockObject(BLACK_BRUSH);
	WinClass->lpszMenuName	= NULL;
	WinClass->lpszClassName	= WINCLASSSTRING;
	WinClass->hIconSm		= LoadIcon(NULL, IDI_APPLICATION);

	WinClassAtom = RegisterClassEx(WinClass);
	assert(WinClassAtom != 0);

	return WINCLASSSTRING;

}

UIWindow *uiwinMake(void) {
	UIWinWindow *uiw;
	uiw = memCopy(&blankuiwinwindow, sizeof(UIWinWindow), "UIWinWindow", NULL);
	return (UIWindow *)uiw;
}

void uiwwInit(UIWinWindow *uiww) {
	//HDC hdc;
	//uiwGetClass();
	/*uiww->hwnd = CreateWindowEx(WS_EX_APPWINDOW, 
	//uiww->hwnd = CreateWindow(
			//(void *) WinClassAtom, 
			//uiwGetClass(), 
			WINCLASSSTRING,
			//"isproxy",
			uiww->uiw.caption, 
			WS_POPUPWINDOW | WS_CAPTION, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
			NULL, NULL, hinst, NULL);

	if(uiww->hwnd == NULL) {
		DWORD err = GetLastError();
	}
	*/
	//hdc = GetDC(uiww->hwnd);
	//DeleteObject(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)));
	//ReleaseDC(uiww->hwnd, hdc);

	uiww->cstyle = DS_CENTER | DS_3DLOOK | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU;
	uiww->cexstyle = 0;
}
void uiwwFree(UIWinWindow *uiww) {
	//todo: cycle through uica and release controls
	DestroyWindow(uiww->hwnd);
	uiwhDelete(uiww);
}

void uiwwRun(UIWinWindow *uiww) {
//	RECT rect;
	WORD *p;
	LPCDLGTEMPLATE dialog;

	int xmargin = 8;
	int ymargin = 8;

	int xx = 480;

	int x = xx - xmargin * 2;
	int y = ymargin;


	int i = 0;
	MSG msg;

	uiwwSizeGroup(uiww, &i, &x, &y, xmargin, ymargin);

	uiww->x = 0;
	uiww->y = 0;
	uiww->w = xx;
	uiww->h = y;

/*
	MoveWindow(uiww->hwnd, 0, 0, xx, y, TRUE);
	GetClientRect(uiww->hwnd, &rect);
	xx += xx - rect.right;
	y += y - rect.bottom;
	MoveWindow(uiww->hwnd, 0, 0, xx, y, TRUE);

	ShowWindow(uiww->hwnd, SW_SHOW);
	uiwhDelete(uiww);
	uiwhAdd(uiww, uiww->hwnd);
	uiww->active = UIWIN_ACTIVE;
	while(uiww->active == UIWIN_ACTIVE) {
		GetMessage(&msg, uiww->hwnd, 0, 0);
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	uiww->active = UIWIN_INACTIVE;
	uiwhDelete(uiww);
	ShowWindow(uiww->hwnd, SW_HIDE);
*/

	//todo:centre window properly
	//todo:adjust size to have proper inside area.
/*
	rect.left = uiww->x;
	rect.top = uiww->y;
	rect.right = uiww->x + uiww->w;
	rect.bottom = uiww->y + uiww->h;
	AdjustWindowRectEx(&rect, uiww->cstyle, FALSE, uiww->cexstyle);
	uiww->x = rect.left;
	uiww->y = rect.top;
	uiww->w = rect.right - rect.left;
	uiww->h = rect.bottom - rect.top;
*/	
//	uiww->w += 8;
//	uiww->h += 24;

	p = uiwwToDialog(uiww);
	dialog = (LPCDLGTEMPLATE) DWORDALIGN(p);
/*
	uiwhAdd(uiww, NULL);
	uiww->active = UIWIN_ACTIVE; //todo: move this into the notify function
	//DialogBoxIndirect(hinst, dialog, NULL, uiwwNotify);
	//todo: maybe: consider CreateDialogIndirect() instead
	uiww->active = UIWIN_INACTIVE; //todo: move this into the notify function
	uiwhDelete(uiww);
*/
	uiwhAdd(uiww, NULL);
	uiww->hwnd = CreateDialogIndirect(hinst, dialog, NULL, uiwwNotify);
	//uiwhAdd(uiww, uiww->hwnd);
	uiwhHideOthers(uiww->hwnd);
	uiwhShow(uiww->hwnd);
	//ShowWindow(uiww->hwnd, SW_SHOW);
	uiww->active = UIWIN_ACTIVE;
	while(uiww->active == UIWIN_ACTIVE) {
		uiwhShow(uiww->hwnd);
		GetMessage(&msg, NULL, 0, 0);//uiww->hwnd, 0, 0);
		if(IsDialogMessage(uiww->hwnd, &msg) == 0) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		coreMainPoll(1);
	}
	uiww->active = UIWIN_INACTIVE;
	ShowWindow(uiww->hwnd, SW_HIDE);
	DestroyWindow(uiww->hwnd);
	uiwhDelete(uiww);
	
	memFree(p);

}

void uiwwSizeGroup(UIWinWindow *uiww, int *i, int *x, int *y, int xmargin, int ymargin) {
	UIWinControl *uiwc;
	int xx;
	int cx;
	int cy;
	int cys;
	int cw;
	int ch;
	HWND hwnd;
	//for(; *i < uiww->uiw.uica->size; *i++) {
	while(*i < uiww->uiw.uica->size) {
		uiwc = (UIWinControl *) uiww->uiw.uica->data[*i];
		cx = xmargin;
		cy = *y;
		cw = *x;//*x - xmargin * 2;
		hwnd = uiwc->hwnd;
		switch(uiwc->uic.entry.type) {
		case UITYPE_BUTTON:
		case UITYPE_BUTTONOK:
		case UITYPE_BUTTONCANCEL:
			cx += (cw - BUTTON_WIDTH) / 2;
			cw = BUTTON_WIDTH;
			ch = 32;//24;
			(*y) += 4;
			cy += 4;
			cys = 4;
			break;
		case UITYPE_EDIT:
			ch = 24;
			cys = 4;
			break;
		case UITYPE_EDIT_LONG:
			ch = 88;
			cys = 4;
			break;
		case UITYPE_CHECK:
		case UITYPE_RADIO:
			ch = 16;
			cys = 0;
			break;
		case UITYPE_TEXT:
			ch = 16;
			cys = 4;
			break;
		case UITYPE_BOXSTART:
			ch = *y;
			(*i)++;
			(*y) += 20;
			xx = *x - 16;
			uiwwSizeGroup(uiww, i, &xx, y, xmargin + 8, ymargin);
			ch = *y - cy + 4;
			cys = -ch + 12;
			break;
		case UITYPE_COLUMN_START_2:
			(*y) += 4;
			(*i)++;
			xx = cw / 2 - 8;
			uiwwSizeGroup(uiww, i, &xx, y, xmargin, ymargin);
			ch = *y - cy;
			*y = cy + 4;
			(*i)++;
			uiwwSizeGroup(uiww, i, &xx, y, xmargin + cw / 2 + 8, ymargin);
			if((*y - cy) > ch) {
				ch = *y - cy;
			}
			*y = ch + cy + 4;
			//todo:
			break;
		case UITYPE_COLUMN_STOP:
		case UITYPE_BOXSTOP:
			//(*i)++;
			return;
		case UITYPE_NONE:
		case UITYPE_RADIOSTART:
		case UITYPE_RADIOSTOP:
		default:
			cw = 0;
			ch = 0;
			cys = 0;
		}
		if(ch != 0 && uiwc->cclass != NULL) {
			//MoveWindow(hwnd, cx, cy, cw, ch, TRUE);
			uiwc->x = cx;
			uiwc->y = cy;
			uiwc->w = cw;
			uiwc->h = ch;

			(*y) += ch+ cys;
		}
		(*i)++;
	}
}

void uiwwAddControl(UIWinWindow *uiww, UIEntry *uie) {
	//HDC hdc;
	UIEntry uiet;
	UIWinControl *uiwc;
	//LPCTSTR cclass = NULL;
	char *cclass = NULL;
	DWORD cestyle = 0;
	DWORD cstyle = 0;
	uiwc = memAlloc(sizeof(UIWinControl), "UIWinControl", NULL);
	uieCopyAt(&uiwc->uic.entry, uie);

	switch(uie->type) {
	case UITYPE_BUTTON:
		cclass = "BUTTON";
		cstyle = BS_PUSHBUTTON | WS_TABSTOP;
		break;
	case UITYPE_BUTTONOK:
		cclass = "BUTTON";
		cstyle = BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
		break;
	case UITYPE_BUTTONCANCEL:
		cclass = "BUTTON";
		cstyle = BS_PUSHBUTTON | WS_TABSTOP;
		break;
	case UITYPE_EDIT:
		uiet.caption = uie->caption;
		uiet.type = UITYPE_TEXT;
		uiet.id = 0;
		uiet.notifyfunc = NULL;
		uiwwAddControl(uiww, &uiet);

		stringFree(uiwc->uic.entry.caption);
		uiwc->uic.entry.caption = "";

		cclass = "EDIT";
		cstyle = WS_TABSTOP | WS_BORDER;
		//cestyle = WS_EX_CLIENTEDGE;
		break;
	case UITYPE_EDIT_LONG:
		uiet.caption = uie->caption;
		uiet.type = UITYPE_TEXT;
		uiet.id = 0;
		uiet.notifyfunc = NULL;
		uiwwAddControl(uiww, &uiet);

		stringFree(uiwc->uic.entry.caption);
		uiwc->uic.entry.caption = "";

		cclass = "EDIT";
		cstyle = ES_AUTOVSCROLL | ES_MULTILINE |  WS_VSCROLL | WS_TABSTOP | WS_BORDER;
		//cestyle = WS_EX_CLIENTEDGE;
		break;
	case UITYPE_CHECK:
		cclass = "BUTTON";
		cstyle = BS_AUTOCHECKBOX | WS_TABSTOP;
		break;
	case UITYPE_RADIO:
		cclass = "BUTTON";
		cstyle = BS_AUTORADIOBUTTON | WS_TABSTOP;
		if(uiww->startradio != 0) {
			 cstyle |= WS_GROUP;
			uiww->startradio = 0;
		}
		break;
	case UITYPE_RADIOSTART:
		uiww->startradio = 1;
		break;
	case UITYPE_RADIOSTOP:
		break;
	case UITYPE_TEXT:
		cclass = "STATIC";
		break;
	case UITYPE_BOXSTART:
		cclass = "BUTTON";
		cstyle = BS_GROUPBOX;
		break;
	case UITYPE_COLUMN_START_2:
	case UITYPE_COLUMN_STOP:
	case UITYPE_BOXSTOP:
		break;
	case UITYPE_NONE:
		break;
	default:
		LOGERROR(stringJoinMany("uiwwAddControl unhandle control type:", intToString(uiwc->uic.entry.type), NULL));
	}
	if(cclass != NULL) {
		uiww->controlcount++;
		uiwc->cclass = cclass;
		uiwc->cstyle = cstyle  | WS_VISIBLE | WS_CHILD;
		uiwc->cexstyle = cestyle;

		//todo: add control IDs
		//uiwc->hwnd = CreateWindowEx(cestyle, cclass, uiwc->uic.entry.caption, cstyle | WS_VISIBLE | WS_CHILD, 0, 0, 80, 16, uiww->hwnd, NULL, hinst, NULL);

		//hdc = GetDC(uiwc->hwnd);
		//DeleteObject(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)));
		//ReleaseDC(uiwc->hwnd, hdc);
		/*
		if(uiwc->uic.entry.id != 0) {
		*/
			//SetWindowLong(uiwc->hwnd, GWL_ID, uiwc->uic.entry.id + IDBASE);
		/*
		} else {
			SetWindowLong(uiwc->hwnd, GWL_ID, IDBASE - 1);
		}
		*/
	}
	uicaAdd(uiww->uiw.uica, (UIControl *) uiwc);
}

WORD *uidtAddString(WORD *p, char *s) {
	//todo: give this a better character limit (potential heap overflow)
	return p + 1 + MultiByteToWideChar(CP_UTF8, 0, s, strlen(s), p, 512);
	//return p + nCopyAnsiToWideChar(p, s); 
}

WORD *uidtAddControl(WORD *p, UIWinControl *uiwc) {
	*p++ = LOWORD (uiwc->cstyle);
	*p++ = HIWORD (uiwc->cstyle);
	*p++ = LOWORD (uiwc->cexstyle);
	*p++ = HIWORD (uiwc->cexstyle);
	*p++ = uiwc->x / 2;         // x
	*p++ = uiwc->y / 2;         // y
	*p++ = uiwc->w / 2;        // cx
	*p++ = uiwc->h / 2;        // cy
	*p++ = uiwc->uic.entry.id + IDBASE;	// ID
	//p = uidtAddString(p, uiwGetClass()); //class
	p = uidtAddString(p, uiwc->cclass); //class
	p = uidtAddString(p, uiwc->uic.entry.caption); //caption/text
	*p++ = 0;        // no extra data

	return p;
}

void *uiwwToDialog(UIWinWindow *uiww) {
	UIWinControl *uiwc;
	WORD *p;
	WORD *dialog;
	int i;

	if(uiww == NULL) {
		return NULL;
	}

	//todo: change this to an accurate count of all controls and needed sizes (potential heap overflow)
	p = memAlloc(1024 * (1 + uiww->controlcount), "uiwwDialog", NULL);
	dialog = p;//todo: make this safer

	p = DWORDALIGN(p);

	*p++ = LOWORD (uiww->cstyle | DS_SETFONT);
	*p++ = HIWORD (uiww->cstyle | DS_SETFONT);
	*p++ = LOWORD (uiww->cexstyle);
	*p++ = HIWORD (uiww->cexstyle);
	*p++ = uiww->controlcount;	// NumberOfItems
	*p++ = uiww->x / 2;         // x
	*p++ = uiww->y / 2;         // y
	*p++ = uiww->w / 2;        // cx
	*p++ = uiww->h / 2;        // cy
	*p++ = 0;          // Menu
	*p++ = 0;          // Class 
	//p = uidtAddString(p, uiwGetClass()); // Class
	p = uidtAddString(p, uiww->uiw.caption);	//Title
	*p++ = 8;          // PointSize
	p = uidtAddString(p, "MS Sans Serif");	//FontName

	for(i = 0; i < uiww->uiw.uica->size; i++) {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
		if(uiwc->cclass != NULL) {
			p = DWORDALIGN(p);
			p = uidtAddControl(p, uiwc);
		}
	}
	return dialog;
}


int uiwcGetRadio(UIWinWindow *uiww, int index) {
	int i;
	UIWinControl *uiwc;
	for(i = index; i >= 0 && uiww->uiw.uica->data[i]->entry.type != UITYPE_RADIOSTART; i--) {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
		if(SendMessage(uiwc->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) {
			return i;
		}
	}
	for(i = index; i < uiww->uiw.uica->size && uiww->uiw.uica->data[i]->entry.type != UITYPE_RADIOSTOP; i++) {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
		if(SendMessage(uiwc->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) {
			return i;
		}
	}
	return -1;
}

uiwcSetRadio(UIWinWindow *uiww, int index) {
	int i;
	UIWinControl *uiwc;
	i = uiwcGetRadio(uiww, index);
	if(i != -1) {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
		SendMessage(uiwc->hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
	}
	uiwc = (UIWinControl *)uiww->uiw.uica->data[index];
	SendMessage(uiwc->hwnd, BM_SETCHECK, BST_CHECKED, 0);
}

void uiwcSetState(UIWinWindow *uiww, int index, int state) {
	UIWinControl *uiwc;
	uiwc = (UIWinControl *)uiww->uiw.uica->data[index];
	EnableWindow(uiwc->hwnd, (state != UISTATE_NORMAL) ? FALSE : TRUE);
}

void uiwcSetValue(UIWinWindow *uiww, int index) {
	UIWinControl *uiwc;
	uiwc = (UIWinControl *)uiww->uiw.uica->data[index];
	switch(uiwc->uic.entry.type) {
	case UITYPE_RADIO:
		uiwcSetRadio(uiww, index);
		break;
	case UITYPE_CHECK:
		SendMessage(uiwc->hwnd, BM_SETCHECK, (uiwc->uic.value != 0) ? BST_CHECKED : BST_UNCHECKED, 0);
		break;
	case UITYPE_EDIT:
	case UITYPE_EDIT_LONG:
		SetWindowText(uiwc->hwnd, uiwc->uic.stringvalue);
		break;
	}
}


//void uiwwDraw(UIWinWindow *uidw);
//int uiwwDoInput(UIWinWindow *uidw);
int uiwDialog(char *title, char *text, int type, int defaultchoice) {
	int reply;
	int mbtype;
	int mbdef = 0;

	defaultchoice &= type;
	switch(type) {
	case UIDIALOG_YESNO:
		mbtype = MB_YESNO;
		switch(defaultchoice) {
		case UIDIALOG_NO:
			mbdef = MB_DEFBUTTON2;
			break;
		case UIDIALOG_YES:
		default:
			mbdef = MB_DEFBUTTON1;
			break;			
		}
		break;
	case UIDIALOG_YESNOCANCEL:
		mbtype = MB_YESNOCANCEL;
		switch(defaultchoice) {
		case UIDIALOG_CANCEL:
			mbdef = MB_DEFBUTTON3;
			break;
		case UIDIALOG_NO:
			mbdef = MB_DEFBUTTON2;
			break;
		case UIDIALOG_YES:
		default:
			mbdef = MB_DEFBUTTON1;
			break;
		}
		break;
	case UIDIALOG_OKCANCEL:
		mbtype = MB_OKCANCEL;
		switch(defaultchoice) {
		case UIDIALOG_CANCEL:
			mbdef = MB_DEFBUTTON2;
			break;
		case UIDIALOG_OK:
		default:
			mbdef = MB_DEFBUTTON1;
			break;
		}
		break;
	case UIDIALOG_OK:
		mbtype = MB_OK;
		break;
	default:
		return 0;
	}
	reply = MessageBox(NULL, text, title, mbtype | mbdef);
	switch(reply) {
	case IDOK:
		return UIDIALOG_OK;
	case IDCANCEL:
		return UIDIALOG_CANCEL;
	case IDYES:
		return UIDIALOG_YES;
	case IDNO:
		return UIDIALOG_NO;
	}
	return 0;
}


UIWinWindow *uiwwFromHWND(HWND hwnd) {
	UIWinWindow *uiww;
	for(;hwnd != NULL; hwnd = GetWindow(hwnd, GW_OWNER)) {
		uiww = uiwhFind(hwnd);
		if(uiww != NULL) {
			return uiww;
		}
	}
	return NULL;
}

int uiwcFindHWND(UIWinWindow *uiww, HWND hwnd) {
	int i;
	UIWinControl *uiwc;
	for(i = 0; i < uiww->uiw.uica->size; i++) {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
		if(uiwc->hwnd == hwnd) {
			return i;
		}
	}
	return -1;
}


BOOL APIENTRY uiwwNotify(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
	UIWinWindow *uiww;
	int index;
	UIWinControl *uiwc;
	char *s;
	int i;
	int entropyvalue = 0;
	if(message == WM_INITDIALOG) {
		uiww = uiwhFind(NULL);
		uiwhDelete(uiww);
		uiwhAdd(uiww, hwnd);
		//todo: do initialization stuff
		for(i = 0; i < uiww->uiw.uica->size; i++) {
			uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
			if(uiwc->uic.entry.id != 0) {
				uiwc->hwnd = GetDlgItem(hwnd, IDBASE + uiwc->uic.entry.id);
			}
		}
		for(i = 0; i < uiww->uiw.uica->size; i++) {
			uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
			if(uiwc->hwnd != NULL) {
				switch(uiwc->uic.entry.type) {
				case UITYPE_RADIO:
					if(uiwc->uic.value != 0) {
						uiwcSetValue(uiww, i);
					}
					break;
				case UITYPE_EDIT:
				case UITYPE_EDIT_LONG:
				case UITYPE_CHECK:
					uiwcSetValue(uiww, i);
					break;
				}
				uiwcSetState(uiww, i, uiwc->uic.state);
				SetWindowLong(uiwc->hwnd, GWL_EXSTYLE, uiwc->cexstyle);
			}
		}
		return TRUE;
	}

	uiww = uiwwFromHWND(hwnd);
	if(uiww == NULL) {
		//return DefWindowProc(hwnd, message, wParam, lParam);
		return FALSE;
	}

/*
	index = uiwcFindHWND(uiww, hwnd);
	if(index == -1) {
		return DefWindowProc(hwnd, message, wParam, lParam);
	} else {
		uiwc = (UIWinControl *)uiww->uiw.uica->data[index];
	}
*/
	switch(message) {
	case WM_MOUSEMOVE: 
	case WM_KEYUP:
		entropyvalue = 1;
		break;
	default:
		entropyvalue = 0;
		break;
	}
	randomAddEntropy(message, 0);
	randomAddEntropy(wParam, entropyvalue);
	randomAddEntropy(lParam, entropyvalue);
	randomAddEntropyClock(0);

	if(uiww->entropyneed != 0) {
		uiww->entropygot += entropyvalue;
		if(uiww->entropygot >= uiww->entropyneed) {
			uicEnable(&uiww->uiw, ID_BUTTON_UIGE_OK);
		}
	}

	switch(message) {
	case EN_KILLFOCUS:
	case BN_CLICKED:
	case WM_COMMAND:
		if(LOWORD(wParam) == IDBASE - 1) {
			index = -1;
		} else {
			index = uicaFind(uiww->uiw.uica, LOWORD(wParam) - IDBASE);
		}
		if(index == -1) {
			//return DefWindowProc(hwnd, message, wParam, lParam);
			return FALSE;
		}
		uiwc = (UIWinControl *)uiww->uiw.uica->data[index];
		switch(message) {
		case WM_COMMAND:
			switch(uiwc->uic.entry.type) {
			case UITYPE_BUTTON:
			case UITYPE_BUTTONOK:
			case UITYPE_BUTTONCANCEL:
				//a kludge to do the entropy gathering
				if(uiww->entropyneed != 0) {
					uiww->active = UIWIN_INACTIVE;
					EndDialog(hwnd, 0);
					return TRUE;
				}
				if(uiwc->uic.entry.notifyfunc != NULL) {
					if(uiwc->uic.entry.notifyfunc(uiww, uiwc, UINOTIFY_ACTIVATED) == UINOTIFYRETURN_EXIT) {
						uiww->active = UIWIN_INACTIVE;
						EndDialog(hwnd, 0);
					}
				}
				return TRUE;
				break;
/*
			}
			break;
		case BN_CLICKED:
			switch(uiwc->uic.entry.type) {
*/
			case UITYPE_CHECK:
				uiwc->uic.oldvalue = uiwc->uic.value;
				uiwc->uic.value = (SendMessage(uiwc->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0;
				if(uiwc->uic.oldvalue != uiwc->uic.value) {
					if(uiwc->uic.entry.notifyfunc != NULL) {
						if(uiwc->uic.entry.notifyfunc(uiww, uiwc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
							//do nothing
						} else {
							uiwc->uic.value = uiwc->uic.oldvalue;
							SendMessage(uiwc->hwnd, BM_SETCHECK, (uiwc->uic.value != 0) ? BST_CHECKED : BST_UNCHECKED, 0);
						}
					}
					return TRUE;
				}
				break;
			case UITYPE_RADIO:
				//if((uiwc->uic.value != 0) && (!IsDlgButtonChecked(hwnd, uiwc->uic.entry.id + IDBASE))) {
				if(!IsDlgButtonChecked(hwnd, uiwc->uic.entry.id + IDBASE)) {
					break;
				}
				//todo: figure out currently checked radio
				i = uicaClearRadioGroup(uiww->uiw.uica, index);
				//uiwcSetRadio(uiww, index);
				uiwc->uic.value = 1;
				if(uiwc->uic.entry.notifyfunc != NULL) {
					if(uiwc->uic.entry.notifyfunc(uiww, uiwc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
						//do nothing
					} else {
						uicaClearRadioGroup(uiww->uiw.uica, i);
						uiwc = (UIWinControl *)uiww->uiw.uica->data[i];
						uiwc->uic.value = 1;
						uiwcSetRadio(uiww, i);
					}
				}
				return TRUE;
				break;
/*
			}
			break;
		case EN_KILLFOCUS:
			switch(uiwc->uic.entry.type) {
*/
			case UITYPE_EDIT:
			case UITYPE_EDIT_LONG:
				uiwc->uic.oldstringvalue = uiwc->uic.stringvalue;
				s = stringMake(GetWindowTextLength(uiwc->hwnd));
				GetWindowText(uiwc->hwnd, s, GetWindowTextLength(uiwc->hwnd) + 1);
				uiwc->uic.stringvalue = s;
				if(stringCompare(uiwc->uic.oldstringvalue, uiwc->uic.stringvalue) == 0) {
					stringFree(uiwc->uic.stringvalue);
					uiwc->uic.stringvalue = uiwc->uic.oldstringvalue;
				} else {
					if(uiwc->uic.entry.notifyfunc != NULL) {
						if(uiwc->uic.entry.notifyfunc(uiww, uiwc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
							stringFree(uiwc->uic.oldstringvalue);
						} else {
							stringFree(uiwc->uic.stringvalue);
							uiwc->uic.stringvalue = uiwc->uic.oldstringvalue;
							SetWindowText(uiwc->hwnd, uiwc->uic.stringvalue);
						}
					}
				}
				return TRUE;
				break;
			}
			break;
/*
			case UITYPE_COLUMN_START_2:
			case UITYPE_COLUMN_STOP:
			case UITYPE_RADIOSTART:
			case UITYPE_RADIOSTOP:
			case UITYPE_TEXT:
			case UITYPE_BOXSTART:
			case UITYPE_BOXSTOP:
			case UITYPE_NONE:
				break;
			default:
				LOGERROR(stringJoinMany("uiwwNotify unhandle control type:", intToString(uiwc->uic.entry.type), NULL));
			}
*/
		}
/*
	case WM_NEXTDLGCTL:
		i = 0;
		break;
*/
	default:
		break;
	}
	//return DefWindowProc(hwnd, message, wParam, lParam);
	return FALSE;
}

BOOL APIENTRY uiwwcProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
	return DefWindowProc(hwnd, message, wParam, lParam);
}

int uiwGetEntropy(char *title, char *text, int bits) {
	UIWindow *uiw;
	UIWinWindow *uiww;

	if(bits <= 0) {
		return 0;
	}
	uiw = uiwMake(title);

	uiwgetentropy[0].caption = text;

	uiwAddControls(uiw, uiwgetentropy);

	uiww = (UIWinWindow *)uiw;
	uiww->entropyneed = bits;
	uicDisable(&uiww->uiw, ID_BUTTON_UIGE_OK);

	uiwRun(uiw);

	bits = uiww->entropygot;

	uiwFree(uiw);

	return bits;
}

//@}

