//
// ui.c
//
//
//-UserX 2002/03/18
#include <stdlib.h>

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

/**

*/
//@{

UIFuncUIWindowMaker uiwindowmaker = NULL;
UIFuncUIDialog uidialog = NULL;
UIFuncUIGetEntropy uigetentropy = NULL;

UIControl *blankuicontrolptr = NULL;

//UIWindow blankuiwindow = BLANKUIWINDOW;


void uiSetFuncs(UIFuncUIWindowMaker uiwmaker, UIFuncUIDialog uid, UIFuncUIGetEntropy uige) {
	uiwindowmaker = uiwmaker;
	uidialog = uid;
	uigetentropy = uige;
}

/**
Creates a new "window".
@param caption The caption to use on this window, is copied. 
@return Pointer to the new UIWindow handle.
*/
UIWindow *uiwMake(char *caption) {
	UIWindow *uiw;
	LOGMEMDUMP();
	if(uiwindowmaker == NULL) {
		//todo: log error
		return NULL;
	}
	uiw = uiwindowmaker(); //memCopy(&blankuiwindow, sizeof UIWindow, "UIWindow", NULL);//todo: switch to ui specific function
	if(uiw == NULL) {
		LOGERROR("Couldn't create window handle!");
		return NULL;
	}
	uiw->caption = stringCopy(caption);
	uiw->uica = uicaMake();
	uiw->uiwinitfunc(uiw);
	return uiw;
}

/**
Runs a "window" will return once the "window" is "closed".
@param uiw Pointer to the UIWindow handle.
*/
void uiwRun(UIWindow *uiw) {
	LOGMEMDUMP();
	if(uiw == NULL) {
		return;
	}
	uiw->uiwrunfunc(uiw);
	LOGMEMDUMP();
}

/**
Releases all resources held by a UIWindow.
@param uiw Pointer to the UIWindow handle.
*/
void uiwFree(UIWindow *uiw) {
	if(uiw == NULL) {
		return;
	}
	uiw->uiwfreefunc(uiw);

	uicaFree(uiw->uica);
	stringFree(uiw->caption);

	memFree(uiw);
	LOGMEMDUMP();
}

/**
Adds list controls to a "window". 
@param uiw Pointer to the UIWindow handle. 
@param uiea An array of UIEntry terminated with a BLANKUIENTRY. 
*/
void uiwAddControls(UIWindow *uiw, UIEntry *uiea) {
	int i;
	if(uiea == NULL) {
		return;
	}
	for(i = 0; uiea[i].type != UITYPE_NONE; i++) {
		uiw->uiaddcontrolfunc(uiw, &uiea[i]);
	}
}

UIControlArrayHandle *uicaMake(void) {
	return (UIControlArrayHandle *)arrayMake(sizeof(UIControl *), 0, &blankuicontrolptr, NULL, (ArrayFuncDelete) uicFreeAt);
}

void uicaFree(UIControlArrayHandle *uica) {
	arrayFree((ArrayHandle *)uica);
}

int uicaFind(UIControlArrayHandle *uica, int id) {
	int i;
	if(uica == NULL) {
		return -1;
	}
	for(i = 0; i < uica->size; i++) {
		if(uica->data[i]->entry.id == id) {
			return i;
		}
	}
	return -1;
}

void uicaAdd(UIControlArrayHandle *uica, UIControl *uic) {
	if(uica == NULL) {
		return;
	}
	arrayInsert((ArrayHandle *)uica, uica->size, 1);
	uica->data[uica->size - 1] = uic;
}

int uicaClearRadioGroup(UIControlArrayHandle *uica, int index) {
	int i;
	for(i = index; i >= 0 && uica->data[i]->entry.type != UITYPE_RADIOSTART; i--) {
		if(uica->data[i]->value != 0) {
			uica->data[i]->value = 0;
			return i;
		}
	}
	for(i = index; i < uica->size && uica->data[i]->entry.type != UITYPE_RADIOSTOP; i++) {
		if(uica->data[i]->value != 0) {
			uica->data[i]->value = 0;
			return i;
		}
	}
	//todo: consider -1 instead
	return index;
}

void uicFreeAt(UIControl **uic) {
	if(uic == NULL) {
		return;
	}
	if(*uic == NULL) {
		return;
	}
	stringFree((*uic)->oldstringvalue);
	stringFree((*uic)->stringvalue);
	uieFree(&(*uic)->entry);
	memFree(*uic);
}

void uieCopyAt(UIEntry *uie, UIEntry *uies) {
	*uie = *uies;
	uie->caption = stringCopy(_(uies->caption));
}

void uieFree(UIEntry *uie) {
	stringFree(uie->caption);
}

/**
Enables a control.
@param uiw Pointer to the UIWindow handle.
@param id The ID of the control. 
*/
void uicEnable(UIWindow *uiw, int id) {
	int index;
	if(uiw == NULL) {
		return;
	}
	index = uicaFind(uiw->uica, id);
	//todo: sanity checking
	if(index == -1) {
		return;
	}
	uiw->uica->data[index]->state = UISTATE_NORMAL;
	uiw->uicsetstatefunc(uiw, index, UISTATE_NORMAL);
}

/**
Disables a control.
@param uiw Pointer to the UIWindow handle.
@param id The ID of the control. 
*/
void uicDisable(UIWindow *uiw, int id) {
	int index;
	if(uiw == NULL) {
		return;
	}
	index = uicaFind(uiw->uica, id);
	//todo: sanity checking
	if(index == -1) {
		return;
	}
	uiw->uica->data[index]->state = UISTATE_DISABLED;
	uiw->uicsetstatefunc(uiw, index, UISTATE_DISABLED);
}

/**
Set/clears a check box.
@param uiw Pointer to the UIWindow handle.
@param id The ID of the control. 
@param value Zero for un-checked, non-zero for checked.
*/
void uicSetCheck(UIWindow *uiw, int id, int value) {
	int index;
	index = uicaFind(uiw->uica, id);
	//todo: sanity checking
	uiw->uica->data[index]->value = (value != 0) ? 1 : 0;
	uiw->uicsetvaluefunc(uiw, index);
}

/**
Sets a radio button, clears all others in the group. 
@param uiw Pointer to the UIWindow handle. 
@param id The ID of the control. 
*/
void uicSetRadio(UIWindow *uiw, int id){
	int index;
	index = uicaFind(uiw->uica, id);
	//todo: sanity checking
	uicaClearRadioGroup(uiw->uica, index);
	uiw->uica->data[index]->value = 1;
	uiw->uicsetvaluefunc(uiw, index);
}

/**
Sets a radio button, clears all others in the group. 
@param uiw Pointer to the UIWindow handle. 
@param id The ID of the control. 
@param string Pointer to the new string to use. 
*/
void uicSetString(UIWindow *uiw, int id, char *string) {
	int index;
	index = uicaFind(uiw->uica, id);
	//todo: sanity checking
	stringFree(uiw->uica->data[index]->stringvalue);
	uiw->uica->data[index]->stringvalue = stringCopy(string);
	uiw->uicsetvaluefunc(uiw, index);
}

int uicGetRadio(UIWindow *uiw, int id) {
	int index;
	int i;
	index = uicaFind(uiw->uica, id);
	for(i = index; i >= 0 && uiw->uica->data[i]->entry.type != UITYPE_RADIOSTART; i--) {
		if(uiw->uica->data[i]->value != 0) {
			return uiw->uica->data[i]->entry.id;
		}
	}
	for(i = index; i < uiw->uica->size && uiw->uica->data[i]->entry.type != UITYPE_RADIOSTOP; i++) {
		if(uiw->uica->data[i]->value != 0) {
			return uiw->uica->data[i]->entry.id;
		}
	}
	//return uiw->uica->data[index]->entry.id;
	return -1;
}

int uicGetValue(UIWindow *uiw, int id) {
	return uiw->uica->data[uicaFind(uiw->uica, id)]->value;
}

char *uicGetString(UIWindow *uiw, int id) {
	return uiw->uica->data[uicaFind(uiw->uica, id)]->stringvalue;
}

/**
Present the user with a message box style thing.
@param title Title caption of the message box. This maybe omitted under some UI schemes.
@param text The message/question.
@param type The type (currently what menu choices it gives you).
@param defaultchoice Which choice it should default to.
*/
int uiDialog(char *title, char *text, int type, int defaultchoice) {
	int i;
	if(uidialog == NULL) {
		//todo: log error
		return 0;
	}
	LOGMEMDUMP();
	i = uidialog(title, text, type, defaultchoice);
	LOGMEMDUMP();
	return i;
}

/**

*/
int uiGetEntropy(char *title, char *text, int bits) {
	int i;
	if(uigetentropy == NULL) {
		//todo: log error
		return 0;
	}
	LOGMEMDUMP();
	i = uigetentropy(title, text, bits);
	LOGMEMDUMP();
	return i;
}
//@}
