#include <stdio.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "hzinput.h"
#include "OptionConfig.h"
#include "kolelog.h"

#define MAX_LINE_LEN	256

int 		gIMEOptionsNum;
IMEOption_Item	*gIMEOptions[MAX_ENGINE_NUM];
 		
IMEOption_Item *OptionItem_Malloc()
{
	IMEOption_Item *pOptionItem;

	pOptionItem = (IMEOption_Item *)calloc(1, sizeof(IMEOption_Item));
	if (pOptionItem == NULL) return(NULL);

	pOptionItem->ime_ename = NULL;
	pOptionItem->ime_cname = NULL;
	pOptionItem->args_list = NULL;

	return(pOptionItem);
}

void OptionItem_Free(IMEOption_Item *pOptionItem)
{
	int i;
	char *arg_name;

	if (pOptionItem == NULL) return;

	if (pOptionItem->ime_ename) 
		free((char *)pOptionItem->ime_ename);
	if (pOptionItem->ime_cname)
		free((char *)pOptionItem->ime_cname);

	if (pOptionItem->args_list) {
		for (i=0; i<MAX_ARGS_NUM; i++) {
			arg_name = pOptionItem->args_list->args[i].name;
			if (arg_name)
				free((char *)arg_name);
		}
		free((char *)pOptionItem->args_list);
	}

	free((char *)pOptionItem);
}

void OptionsList_Init()
{
	int i;
	
	gIMEOptionsNum = 0;
	for (i=0; i<MAX_ENGINE_NUM; i++) 
		gIMEOptions[i] = NULL;
}

void OptionsList_Free()
{
	int i;

	for (i=0; i<MAX_ENGINE_NUM; i++) {
		OptionItem_Free(gIMEOptions[i]);
		gIMEOptions[i] = NULL;
	}

	gIMEOptionsNum = 0;
}

void get_option_line(FILE *fd, char *line)
{
	int line_ptr;
	char line_buf[256], *ptr;

	line_ptr = 0;
	line[0] = '\0';

	/* get line with no space */
 	while(fgets(line_buf, 255, fd) != NULL) {
		ptr = line_buf;

		/* skip space keys */
		while(*ptr && isspace(*ptr)) ptr++;

		/* if is space line, get new line */
		if (*ptr == '\n' || *ptr == '\0')
			continue;

		while(*ptr != '\n' && *ptr != '\0' && line_ptr < MAX_LINE_LEN) 
			line[line_ptr++] = *ptr++;

		/* trim right space */
		while (isspace(line[line_ptr-1])) line_ptr--;
		line[line_ptr] = '\0';

		/* if the line end with '\', then continue read the next line */
		if (line[line_ptr-1] == '\\') {
			line_ptr--;
			line[line_ptr] = '\0';
			continue;
		}

		break;
	}
}

void Get_OptionsList_From_Profile()
{
    	char            file_name[256], line[MAX_LINE_LEN]; 
	int 		i;
	IMEOption_Item	*pOptionItem;
    
	register char 	*ptr, *ime_ename, *pOption_Value;
	FILE 		*fd;

	char 		*locale_name;

	locale_name = setlocale(LC_CTYPE, NULL);

	/* read profile from file to memory buffer  */ 
	sprintf(file_name, "%s/%s/%s/%s", getenv("HOME"), 
		USER_PROFILE_PATH, locale_name, USER_OPTION_FILE_NAME);
	KOLE_LOG (LOGDEST_STDOUT, "file name :%s\n",file_name);

	fd = fopen(file_name, "r");
	if (! fd) {
		return;
	}

	gIMEOptionsNum = 0;
	do {
		get_option_line(fd, line);

		if (line[0] == '\0') break;
		if (line[0] == '#') continue;

		/* get IME language engine name */
		ime_ename = line;
		ptr = line;
		while (*ptr && !isspace(*ptr)) ptr++;
		if (*ptr) {
			*ptr = '\0';
			ptr++;
		}

		/* skip space */
		while (*ptr && isspace(*ptr)) ptr++;

		/* get option value */
		pOption_Value = ptr;
		while (*ptr && !isspace(*ptr)) ptr++;
		if (*ptr) {
			*ptr = '\0';
		}

		pOptionItem = (IMEOption_Item *)OptionItem_Malloc();
		if (pOptionItem == NULL) continue;

		pOptionItem->ime_ename = (char *)strdup(ime_ename);
		if (pOptionItem->ime_ename == NULL) {
			OptionItem_Free(pOptionItem);
			break;
		}
	
		pOptionItem->ime_cname = NULL;
		pOptionItem->opt_value = atol(pOption_Value);
		pOptionItem->args_list = NULL;
		gIMEOptions[gIMEOptionsNum] = pOptionItem;
		gIMEOptionsNum ++;
	} while (1);

	fclose(fd);

	for (i=0; i<gIMEOptionsNum; i++) {
		KOLE_LOG (LOGDEST_STDOUT, "IME Name: %s,  Option: %d\n", 
			gIMEOptions[i]->ime_ename,
			gIMEOptions[i]->opt_value);
	}
    	return;
}

void Save_OptionsList_To_Profile()
{
	FILE *fd;
	int ret, i;
	struct stat file_stat;
	char path_name[256], tmp_name[256];
	char *locale_name;

	/* Create Path $(HOME)/.Xlocale */
	sprintf(path_name, "%s/%s", (char *)getenv("HOME"), USER_PROFILE_PATH);
	KOLE_LOG (LOGDEST_STDOUT, "path_name: %s\n", path_name);

	ret = stat(path_name, &file_stat);
	if (ret == -1) {
		KOLE_LOG (LOGDEST_STDOUT, "%s not exist\n", path_name);
		ret = mkdir(path_name, 0777);
		if (ret == -1) {
			KOLE_LOG (LOGDEST_STDOUT, "can not create path %s\n", path_name);
			return;
		}
	}

	/* Create Path $(HOME)/.Xlocale/<locale> */
	locale_name = setlocale(LC_CTYPE, NULL);

	sprintf(tmp_name, "%s/%s", path_name, locale_name);
	strcpy(path_name, tmp_name);
	KOLE_LOG (LOGDEST_STDOUT, "path_name: %s\n", path_name);

	ret = stat(path_name, &file_stat);
	if (ret == -1) {
		KOLE_LOG (LOGDEST_STDOUT, "%s not exist\n", path_name);
		ret = mkdir(path_name, 0777);
		if (ret == -1) {
			KOLE_LOG (LOGDEST_STDOUT, "can not create path %s\n", path_name);
			return;
		}
	}

	/* Create File $(HOME)/.Xlocale/<locale>/option.cfg */
	sprintf(tmp_name, "%s/%s", path_name, USER_OPTION_FILE_NAME);
	strcpy(path_name, tmp_name);
	KOLE_LOG (LOGDEST_STDOUT, "path_name: %s\n", path_name);
	fd = fopen(path_name, "wb");
	if (! fd) {
		KOLE_LOG (LOGDEST_STDOUT, "unable open the file: %s\n", path_name);
		return;
	}

	for (i=0; i<gIMEOptionsNum; i++) {
		fprintf(fd, "%s\t%d\n", gIMEOptions[i]->ime_ename, gIMEOptions[i]->opt_value);
	}

	fclose(fd);
}

void Add_OptionItem_To_List(IMEOption_Item *pOptionItem)
{
	int  i;
	char *name;
	IMEOption_Item *pNewOptionItem;

	if (pOptionItem == NULL) return;

	pNewOptionItem = (IMEOption_Item *)OptionItem_Malloc();
	if (pNewOptionItem == NULL) return;

	name = (char *)pOptionItem->ime_ename;
	if (name && *name) {
		pNewOptionItem->ime_ename = (char *)strdup(name);
 		if (pNewOptionItem->ime_ename == NULL) {
			OptionItem_Free(pNewOptionItem);
			return;
		}
	}

	name = (char *)pOptionItem->ime_cname;
	if (name && *name) {
		pNewOptionItem->ime_cname = (char *)strdup(name);
		if (pNewOptionItem->ime_cname == NULL) {
			OptionItem_Free(pNewOptionItem);
			return;
		}
	}

	pNewOptionItem->opt_value = pOptionItem->opt_value;

	pNewOptionItem->args_list = (IMEArgListRec *)calloc(1, sizeof(IMEArgListRec));
	if (pNewOptionItem->args_list == NULL) {
		OptionItem_Free(pNewOptionItem);
		return;
	}

	pNewOptionItem->args_list->args_num = pOptionItem->args_list->args_num;
	for (i=0; i<MAX_ARGS_NUM; i++) {
		int arg_type, arg_value;
		char *arg_name;

		pNewOptionItem->args_list->args[i].name = NULL;
		arg_name = (char *)pOptionItem->args_list->args[i].name;
		if (arg_name && *arg_name)
			pNewOptionItem->args_list->args[i].name = (char *)strdup(arg_name);
		
		pNewOptionItem->args_list->args[i].type = pOptionItem->args_list->args[i].type;
		pNewOptionItem->args_list->args[i].value = pOptionItem->args_list->args[i].value;
	}

	if (gIMEOptions[gIMEOptionsNum]) OptionItem_Free(gIMEOptions[gIMEOptionsNum]);

	gIMEOptions[gIMEOptionsNum] = pNewOptionItem;
	gIMEOptionsNum ++;
}


void Set_OptionValue_From_ArgList(IMEOption_Item *pOptionItem)
{
	int  i, j, opt_value;
	int cur_bit_pos, cur_bit_len, value, mask;

	if (pOptionItem->args_list == NULL) return;

	opt_value = 0;
	cur_bit_pos = 0;

	for (i=0; i<pOptionItem->args_list->args_num; i++) {
		value = pOptionItem->args_list->args[i].value;

		cur_bit_len = pOptionItem->args_list->args[i].type;
		if (cur_bit_len <= 0) {
			cur_bit_len = 1;
			value = (value ? 1: 0);
		}

		mask = 0;
		for (j=0; j<cur_bit_len; j++) 
			mask |= (1 << j);

		opt_value |= ((value & mask) << cur_bit_pos);

		cur_bit_pos += cur_bit_len;
	}

	pOptionItem->opt_value = opt_value;
}

void Set_ArgList_From_OptionValue(IMEOption_Item *pOptionItem)
{
	int  i, args_num, opt_value;
	int  cur_bit_pos, cur_bit_len, mask, j;

	if (pOptionItem->args_list == NULL) return;

	args_num = pOptionItem->args_list->args_num;
	opt_value = pOptionItem->opt_value;

	cur_bit_pos = 0;
	for (i=0; i<args_num; i++) {
		if (pOptionItem->args_list->args[i].name == NULL)
			continue;

		cur_bit_len = pOptionItem->args_list->args[i].type;
		if (cur_bit_len <= 0) {
			cur_bit_len = 1;
		}

		mask = 0;
		for (j=0; j<cur_bit_len; j++)
			mask |= (1<<j);

		pOptionItem->args_list->args[i].value = (opt_value >> cur_bit_pos) & mask;

		cur_bit_pos += cur_bit_len;
	}
}


