#include <stdio.h>

#include "config.h"
#include "vkb_layout.h"

#define MAX_LINE_LEN 		256

#define LABEL_STR		"LABEL"
#define TYPE_STR		"TYPE"
#define ENCODE_STR		"ENCODE"
#define STRING_TYPE_STR		"COMMIT_AS_STRING"
#define KEY_TYPE_STR		"COMMIT_AS_KEY"
#define LIST_BEGIN_STR		"LIST_BEGIN"
#define LIST_END_STR		"LIST_END"

static vkb_layout_t *vkb_layout_new()
{
    int i;
    vkb_layout_t *vkb_layout = NULL;

    vkb_layout = (vkb_layout_t *) calloc(1, sizeof(vkb_layout_t));
    if (vkb_layout == NULL)
	return (NULL);

    vkb_layout->ename = NULL;
    vkb_layout->name_utf8 = NULL;
    vkb_layout->type = KEYBOARD_STRING_TYPE;

    for (i = 0; i < MAX_BASEKEY_NUM; i++) {
	vkb_layout->basekey[i].lower_str = NULL;
	vkb_layout->basekey[i].upper_str = NULL;
    }

    return (vkb_layout);
}

static void vkb_layout_destroy(vkb_layout_t * vkb_layout)
{
    int i;

    if (vkb_layout == NULL)
	return;

    if (vkb_layout->ename)
	free ((char *)vkb_layout->ename);

    if (vkb_layout->name_utf8)
	free ((char *)vkb_layout->name_utf8);

    for (i = 0; i < MAX_BASEKEY_NUM; i++) {
	if (vkb_layout->basekey[i].lower_str) {
		free((char *)vkb_layout->basekey[i].lower_str);
	if (vkb_layout->basekey[i].upper_str)
		free((char *)vkb_layout->basekey[i].upper_str);
	}
    }

    free((char *) vkb_layout);
    return;
}

void vkb_layout_print(vkb_layout_t * vkb_layout)
{
    int  i;
    char *label_str;

    if (vkb_layout == NULL)
	return;

    label_str = KEYLIST_LOWER;
    if (vkb_layout->ename)
	printf("ename:%s#\n", vkb_layout->ename);

    if (vkb_layout->name_utf8)
	printf("name_utf8:%s#\n", vkb_layout->name_utf8);

    for (i = 0; i < MAX_BASEKEY_NUM; i++) {
	if (vkb_layout->basekey[i].lower_str) {
	    printf("%c:#%s#       ", *(label_str + i),
		   vkb_layout->basekey[i].lower_str);
	    if (vkb_layout->basekey[i].upper_str)
		printf("#%s#", vkb_layout->basekey[i].upper_str);
	    printf("\n");
	}
    }
}

static void vkb_layout_set_ctrlkey_label(vkb_layout_t * vkb_layout)
{
    if (vkb_layout == NULL)
	return;

    vkb_layout->ctrlkey[VK_BackSpace].label_str = BACKSPACE_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Tab].label_str = TAB_KEY_LABEL;
    vkb_layout->ctrlkey[VK_CapsLock].label_str = CAPS_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Enter].label_str = ENTER_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Shift_L].label_str = SHIFT_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Control_L].label_str = CTRL_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Alt_L].label_str = ALT_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Space].label_str = SPACE_KEY_LABEL;
    vkb_layout->ctrlkey[VK_Escape].label_str = ESCAPE_KEY_LABEL;
}

static void vkb_layout_set_basekey_label(vkb_layout_t * vkb_layout,
					 char *line)
{

    char ch, i, index;
    char *ptr, *lower_str, *upper_str, *label_str;

    if (vkb_layout == NULL)
	return;

    if (!line || !*line)
	return;

    ch = tolower(line[0]);

    label_str = KEYLIST_LOWER;
    index = 0;
    for (i = 0; i < strlen(label_str); i++) {
	if (ch == *(label_str + i)) {
	    index = i;
	    break;
	}
    }

    /* skip spaces */
    ptr = line + 1;
    while (*ptr && isspace(*ptr))
	ptr++;
    lower_str = ptr;

    /* skip to space */
    while (*ptr && !isspace(*ptr))
	ptr++;
    if (*ptr) {
	*ptr = '\0';
	ptr++;
    }

    while (*ptr && isspace(*ptr))
	ptr++;
    upper_str = ptr;

    while (*ptr && !isspace(*ptr))
	ptr++;
    *ptr = '\0';

    if (*lower_str) {
	if (vkb_layout->basekey[index].lower_str)
	    free((char *)vkb_layout->basekey[index].lower_str);
	vkb_layout->basekey[index].lower_str = (char *) strdup(lower_str);
    }
    if (*upper_str) {
	if (vkb_layout->basekey[index].upper_str)
	    free((char *)vkb_layout->basekey[index].upper_str);
	vkb_layout->basekey[index].upper_str = (char *) strdup(upper_str);
    }

    return;
}

static void vkb_layout_set_keyboard_ename(vkb_layout_t * vkb_layout,
					  char *ename)
{
    if (vkb_layout == NULL)
	return;

    if (!ename || !*ename)
	return;

    if (vkb_layout->ename)
	free((char *)vkb_layout->ename);
    vkb_layout->ename = (char *) strdup(ename);
    return;
}

static void vkb_layout_set_keyboard_label(vkb_layout_t * vkb_layout,
					  char *name)
{
    if (vkb_layout == NULL)
	return;

    if (!name || !*name)
	return;

    if (vkb_layout->name_utf8)
	free((char *)vkb_layout->name_utf8);
    vkb_layout->name_utf8 = (char *) strdup(name);
    return;
}

#define VKB_LAYOUT_NUM_ALLOC  6 

static vkb_layout_t **vkb_layout_list_new()
{
    vkb_layout_t **vkb_layout_list = NULL;
    vkb_layout_list =
	(vkb_layout_t **) calloc(VKB_LAYOUT_NUM_ALLOC,
				 sizeof(vkb_layout_t *));
    return (vkb_layout_list);
}

static vkb_layout_t **vkb_layout_list_realloc(vkb_layout_t **
					      vkb_layout_list, int num)
{
    vkb_layout_t **vkb_layout_list_new1 = NULL;
    vkb_layout_list_new1 =
	(vkb_layout_t **) realloc(vkb_layout_list,
				  num * sizeof(vkb_layout_t *));
    return (vkb_layout_list_new1);
}

void vkb_layout_list_destroy(vkb_layout_t ** vkb_layout_list)
{
    vkb_layout_t **p;

    if (vkb_layout_list == NULL)
	return;

    for (p = vkb_layout_list; *p; p++) {
	vkb_layout_destroy(*p);
    }

    free((char *)vkb_layout_list);
}

void vkb_layout_list_print(vkb_layout_t ** vkb_layout_list)
{
    vkb_layout_t **p;

    if (vkb_layout_list == NULL)
	return;

    for (p = vkb_layout_list; *p; p++) {
	vkb_layout_print(*p);
    }
}

static void vkb_layout_get_line_from_file(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;
    }
}

/*
  For keyboard_layout.txt

  Format as follow:

  [ english name ]
  LABEL	chinese name
  TYPE  	COMMIT_AS_STRING/COMMIT_AS_KEY
  ENCODE  UTF-8
  LIST_BEGIN
  a   	lower_str	upper_str
  LIST_END

*/
vkb_layout_t **vkb_layout_list_read_from_layout_file(char *layout_file_name)
{
    FILE *fd;
    char line[MAX_LINE_LEN];
    char *ptr, *ename_str;
    int i, len;
    int list_began = 0;

    int num_vkb_layout;
    vkb_layout_t *vkb_layout;
    vkb_layout_t **vkb_layout_list;

    fd = fopen(layout_file_name, "r");
    if (!fd)
	return (NULL);

    vkb_layout_list = (vkb_layout_t **) vkb_layout_list_new();
    if (vkb_layout_list == NULL)
	return (NULL);

    num_vkb_layout = 0;
    do {
	vkb_layout_get_line_from_file(fd, line);

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

	len = strlen(line);
	if (line[0] == '[' && line[len - 1] == ']') {
	    list_began = 0;
	    if ((num_vkb_layout + 1) % VKB_LAYOUT_NUM_ALLOC == 0) {
		vkb_layout_list = vkb_layout_list_realloc(vkb_layout_list,
							  num_vkb_layout + 1 + VKB_LAYOUT_NUM_ALLOC);
		if (vkb_layout_list == NULL) {
		    return (NULL);
		}
		for (i = num_vkb_layout; i < num_vkb_layout + 1 + VKB_LAYOUT_NUM_ALLOC; i++)
		    vkb_layout_list[i] = NULL;
	    }

	    vkb_layout = (vkb_layout_t *) vkb_layout_new();
	    if (vkb_layout == NULL)
		break;

	    /* get english name of the item */
	    ptr = line + 1;
	    while (isspace(*ptr))
		ptr++;

	    ename_str = ptr;

	    ptr = line + len - 2;
	    while (isspace(*ptr))
		ptr--;
	    *(ptr + 1) = '\0';

	    if (*ename_str)
	        vkb_layout_set_keyboard_ename(vkb_layout, ename_str);
	    vkb_layout_set_ctrlkey_label(vkb_layout);

	    vkb_layout_list[num_vkb_layout] = vkb_layout;
	    num_vkb_layout++;

	    continue;
	}

	if (!(strncasecmp(line, LABEL_STR, strlen(LABEL_STR)))) {
	    ptr = line + strlen(LABEL_STR);
	    while (*ptr && isspace(*ptr))
		ptr++;
	    if (*ptr)
		vkb_layout_set_keyboard_label(vkb_layout, ptr);
	    continue;
	}

	if (!(strncasecmp(line, TYPE_STR, strlen(TYPE_STR)))) {
	    ptr = line + strlen(TYPE_STR);
	    while (*ptr && isspace(*ptr))
		ptr++;
	    if (*ptr) {
		if (!(strncasecmp(ptr, KEY_TYPE_STR, strlen(KEY_TYPE_STR)))) {
		    vkb_layout->type = KEYBOARD_KEY_TYPE;
		} else {
		    vkb_layout->type = KEYBOARD_STRING_TYPE;
		}
	    }
	    continue;
	}

	if (!(strncasecmp(line, LIST_BEGIN_STR, strlen(LIST_BEGIN_STR)))) {
	    list_began = 1;
	    continue;
	}

	if (!(strncasecmp(line, LIST_END_STR, strlen(LIST_END_STR)))) {
	    list_began = 0;
	    continue;
	}

	if (list_began == 1) {
	    vkb_layout_set_basekey_label(vkb_layout, line);
	}
    } while (1);

    fclose(fd);
    return (vkb_layout_list);
}
