#include <stdio.h>
#include <dlfcn.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "imbean.h"
#include "ime_module.h"

extern struct ImmServicesRec le_services;

/*************************************************************/
/*                       ImeModule                           */
/*************************************************************/
ImeModuleRec *ime_module_new()
{
    ImeModuleRec *ime_module = NULL;

    ime_module = (ImeModuleRec *) calloc(1, sizeof(ImeModuleRec));
    if (ime_module != NULL) {
        ime_module->pc_cursor_x = ime_module->pc_cursor_y = 0x80000000;
    }

    return (ime_module);
}

ImeResult ime_module_destroy(ImeModuleRec * ime_module)
{
    if (ime_module == NULL)
	return (IME_OK);

    if (ime_module->methods && ime_module->methods->ImeDestroy)
	ime_module->methods->ImeDestroy(ime_module->info);

    if (ime_module->object_file_path)
	free((char *) ime_module->object_file_path);

    if (ime_module->args)
	free((char *) ime_module->args);

    if (ime_module->module_handler)
	dlclose(ime_module->module_handler);

    free((char *) ime_module);
    return (IME_OK);
}

ImeResult ime_module_print(ImeModuleRec * ime_module)
{
#if DEBUG
    if (ime_module == NULL)
	return (IME_OK);

    printf("\nImeModule: %p\n", ime_module);
    if (ime_module->object_file_path)
	printf("    object_file_path: %s\n", ime_module->object_file_path);

    if (ime_module->args)
	printf("    args: %s\n", ime_module->args);

    if (ime_module->info) {
	if (ime_module->info->version)
	    printf("    version: %d\n", ime_module->info->version);

	if (ime_module->info->uuid)
	    printf("    uuid: %s\n", (char *) ime_module->info->uuid);

	if (ime_module->info->name)
	    printf("    name: %s\n", (char *) ime_module->info->name);

	if (ime_module->info->author)
	    printf("    author: %s\n", (char *) ime_module->info->author);

	if (ime_module->info->copyright)
	    printf("    copyright: %s\n",
		   (char *) ime_module->info->copyright);

	if (ime_module->info->hinting)
	    printf("    hinting: %s\n",
		   (char *) ime_module->info->hinting);

	if (ime_module->info->icon_file)
	    printf("    icon_file: %s\n",
		   (char *) ime_module->info->icon_file);

	if (ime_module->info->support_locales)
	    printf("    support_locales: %s\n",
		   (char *) ime_module->info->support_locales);
    }

    return (IME_OK);
#endif
}

ImeResult ime_module_load_object_file(ImeModuleRec * ime_module,
				      char *basedir, char *ime_object_file,
				      char *ime_args)
{
    void *module_handler = NULL;
    ImeResult (*ime_register_method) ();
    ImeResult result;
    int i, argc = 0;
    char **argv = NULL;

    if (ime_module == NULL)
	return (IME_FAIL);

    module_handler = (void *) dlopen(ime_object_file, RTLD_LAZY);
    if (module_handler == NULL) {
	fprintf(stderr, "Warning: could not open module file: %s\n",
		ime_object_file);
	goto Error;
    }

    ime_module->module_handler = module_handler;

    ime_register_method = dlsym(module_handler, "RegisterIME");
    if (ime_register_method == NULL) {
	fprintf(stderr, "Warning: no 'RegisterIME' method: %s\n",
		ime_object_file);
	goto Error;
    }

    if (ime_args || *ime_args) {
	char *ptr = ime_args;

	if (ime_module->args)
	    free((char *) ime_module->args);
	ime_module->args = (char *) strdup(ime_args);

	/* get the value of argc */
	while (*ptr) {
	    while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
		ptr++;
	    if (*ptr)
		argc++;
	    while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '\n')
		ptr++;
	}

	/* get the value of argv */
#if 0
	argc += 2;
#endif
	DEBUG_printf("ime_args: %s, argc: %d\n", ime_module->args, argc);
	argv = (char **) calloc(argc, sizeof(char *));
	if (argv == NULL) {
	    argc = 0;
	} else {
	    i = 0;
#if 0
	    argv[i++] = "-basedir";
	    argv[i++] = basedir;
#endif
	    ptr = ime_args;
	    while (*ptr) {
		while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
		    ptr++;
		if (*ptr)
		    argv[i++] = ptr;
		while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '\n')
		    ptr++;
		if (*ptr)
		    *(ptr++) = '\0';
	    }
	}
    }

    result = ime_register_method(&le_services, &(ime_module->info),
				 &(ime_module->methods), argc, argv);
    if (argv != NULL)
	free((char *) argv);

    if (result != IME_OK) {
	fprintf(stderr, "Warning: call 'RegisterIME' Failed: %s\n",
		ime_object_file);
	goto Error;
    }

    if (ime_module->info == NULL || ime_module->methods == NULL) {
	fprintf(stderr,
		"Warning: 'RegisterIME' return wrong informations: %s\n",
		ime_object_file);
	goto Error;
    }

    if (ime_module->methods->ImeInitialize != NULL) {
	result = ime_module->methods->ImeInitialize(ime_module->info);
	if (result != IME_OK) {
	    fprintf(stderr, "Warning: call 'ImeInitialize' Failed: %s\n",
		    ime_object_file);
	    goto Error;
	}
    }

    if (ime_module->object_file_path)
	free((char *) ime_module->object_file_path);
    ime_module->object_file_path = (char *) strdup(ime_object_file);

    return (IME_OK);

  Error:
    if (ime_module->object_file_path) {
	free((char *) ime_module->object_file_path);
	ime_module->object_file_path = NULL;
    }

    if (ime_module->args) {
	free((char *) ime_module->args);
	ime_module->args = NULL;
    }

    if (module_handler)
	dlclose(module_handler);
    ime_module->module_handler = NULL;

    return (IME_FAIL);
}

char *standard_error_message[] = {
    "OK",
    "Fail",
    "Register Fail",
};

char *ime_module_get_error_message(ImeModuleRec * ime_module, int error_id)
{

    if (ime_module == NULL)
	return (NULL);

    if (error_id <= IME_OK) {
	return (NULL);
    }

/*
    if (error_id > IME_FAIL && error_id <= IME_ERROR_NUM) {
	return (standard_error_messages[error_id]);
    }
*/

    if (ime_module->methods == NULL)
	return (NULL);
    if (ime_module->methods->ImeGetErrorMessage == NULL)
	return (NULL);

    return ((char *) ime_module->methods->ImeGetErrorMessage(error_id));
}

/*************************************************************/
/*                   ImeModuleContext                        */
/*************************************************************/
ImeModuleContextRec *ime_module_context_new()
{
    ImeModuleContextRec *ime_module_context = NULL;

    ime_module_context =
        (ImeModuleContextRec *) calloc(1, sizeof(ImeModuleContextRec));
    return (ime_module_context);
}

ImeResult ime_module_context_destroy(ImeModuleContextRec *ime_module_context)
{
    if (ime_module_context == NULL)
        return (IME_OK);

    ime_module_destroy(ime_module_context->ime_module);
    free((char *) ime_module_context);

    return (IME_OK);
}

ImeResult ime_module_context_print(ImeModuleContextRec *ime_module_context)
{
#if DEBUG
    if (ime_module_context == NULL)
        return (IME_OK);

    ime_module_print(ime_module_context->ime_module);

    printf("    enabled: %d\n", ime_module_context->enabled);

    return (IME_OK);
#endif
}
