#include <stdio.h>

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

#include "xaux_object.h"

#ifdef USE_AUX_IF_VERSION_2
#include "imbean.h"
#endif

#define MAX_NUM_AUX_MODULES  16 
#define MAX_LEN_CLASS_NAME   128

#define ATOM_NUM_XAUX_MODULE 32

CARD16  utfname_xaux_object[] = {
        'c','o','m','.','s','u','n','.',
        'i','i','i','m','.',
        't','w','l','e','.',
        'a','u','x','.',
        'o','b','j','e','c','t',
};

CARD16  utfname_xaux_manager_gtk2[] = {
        'c','o','m','.','s','u','n','.',
        'i','i','i','m','.',
        't','w','l','e','.',
        'a','u','x','.',
        'm','a','n','a','g','e','r','.',
        'g','t','k','2'
};

CARD16  utfname_xaux_module_palette[] = {
        'c','o','m','.','s','u','n','.',
        'i','i','i','m','.',
        't','w','l','e','.',
        'a','u','x','.',
        'p','a','l','e','t','t','e',
};

CARD16  utfname_xaux_module_composite[] = {
        'c','o','m','.','s','u','n','.',
        'i','i','i','m','.',
        't','w','l','e','.',
        'a','u','x','.',
        'c','o','m','p','o','s','i','t','e',
};

xaux_class_t xaux_classes[MAX_NUM_AUX_MODULES] = {
	{
		XAUX_MODULE_PALETTE_CLASS_NAME,  1,
		LE_AUX_MODULES_DIR "/gtk2/palette_aux_gtk2",
		(Window)0, (Window)0, (Window)0,
		(Atom)0, (Atom)0, (Atom)0,  (Atom)0,
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0, 
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0,
		utfname_xaux_module_palette,
	},
	{
		XAUX_MODULE_COMPOSITE_CLASS_NAME,  1,
		LE_AUX_MODULES_DIR "/gtk2/composite_aux_gtk2",
		(Window)0, (Window)0, (Window)0,
		(Atom)0, (Atom)0, (Atom)0,  (Atom)0,
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0, 
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0,
		utfname_xaux_module_composite,
	},
#if 0
	{
		XAUX_MANAGER_GTK2_CLASS_NAME,  1,
		LE_AUX_MODULES_DIR "/gtk2/aux_manager_gtk2",
		(Window)0, (Window)0, (Window)0,
		(Atom)0, (Atom)0, (Atom)0,  (Atom)0,
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0, 
		{ (Atom)0 }, ATOM_NUM_XAUX_MODULE, 0,
		utfname_xaux_manager_gtk2,
	},
#endif
	{
		NULL,  -1,
		NULL,
		(Window)0, (Window)0, (Window)0,
		(Atom)0, (Atom)0, (Atom)0,  (Atom)0,
		{ (Atom)0 }, 0, 0, 
		{ (Atom)0 }, 0, 0,
		(CARD16 *)NULL,
	},
};

extern aux_method_t xaux_so_methods;

aux_dir_t aux_dir[MAX_NUM_AUX_MODULES] = {
	{
		{ sizeof(utfname_xaux_object),
		  (CARD16 *)utfname_xaux_object,
		},
		&xaux_so_methods,
	},
	{
		{ sizeof(utfname_xaux_module_palette),
		  (CARD16 *)utfname_xaux_module_palette,
		},
		&xaux_so_methods,
	},
	{
		{ sizeof(utfname_xaux_module_composite),
		  (CARD16 *)utfname_xaux_module_composite,
		},
		&xaux_so_methods,
	},
#if 0
	{
		{ sizeof(utfname_xaux_manager_gtk2),
		  (CARD16 *)utfname_xaux_manager_gtk2,
		},
		&xaux_so_methods,
	},
#endif
	{ {0, NULL}, NULL},
};

int aux_classes_print(xaux_class_t *aux_classes)
{
#ifdef DEBUG
	xaux_class_t *p;

	if (aux_classes == NULL) return (AUX_OK);

	printf("\nxaux_classes: \n");
	for (p=aux_classes; p->classname; p++) {
		printf("class_name: %s, exec: %s\n", p->classname, p->extexec);
	}

	return (AUX_OK);
#endif
}

#ifdef USE_AUX_IF_VERSION_2

#define XAUX_MODULES_FILE "aux_modules.xml"

CARD16 utfname_aux_modules_custom[MAX_NUM_AUX_MODULES][MAX_LEN_CLASS_NAME];
char classname_aux_modules_custom[MAX_NUM_AUX_MODULES][MAX_LEN_CLASS_NAME];
char exec_aux_modules_custom[MAX_NUM_AUX_MODULES][MAX_LEN_CLASS_NAME];

int aux_dir_print(aux_dir_t *aux_dir)
{
#ifdef DEBUG
	aux_dir_t *p;

	if (aux_dir == NULL) return (AUX_OK);

	printf("\naux_dir: \n");
	for (p=aux_dir; p->name.ptr; p++) {
		char *class_name = NULL;
		class_name = (char *)xaux_so_get_classname_from_utfname(p->name.ptr, p->name.len);
		if (class_name) {
			printf("class_name: %s, len: %d\n", class_name, p->name.len);
			free ((char *)class_name);
		}
	}

	return (AUX_OK);
#endif
}

char *aux_dir_get_full_file_path(char *file_path)
{
	int len;
	char *full_file_path = NULL;

	if (!file_path || !*file_path)
		return (NULL);

	if (file_path[0] == '/') {
		len = strlen (file_path);

		full_file_path = (char *)calloc(len + 1, sizeof(char));
		if (full_file_path == NULL) return (NULL);

		snprintf(full_file_path, len + 1, "%s", file_path);
	} else {
		len = strlen(LE_AUX_MODULES_DIR) + 1 + strlen (file_path);

		full_file_path = (char *)calloc(len + 1, sizeof(char));
		if (full_file_path == NULL) return (NULL);

		snprintf(full_file_path, len + 1, "%s/%s", LE_AUX_MODULES_DIR, file_path);
	}

	return (full_file_path);
}

int aux_dir_get_custom_aux_modules(char *aux_dir_config_file)
{
#define AUX_MODULE_CLASS_NAME  "class_name"
#define AUX_MODULE_OBJECT_FILE "object_file"

	aux_dir_t *dir;
	int num_aux_dirs;
	int num_aux_dirs_custom;

	xaux_class_t *class;
	int num_aux_classes;
	int num_aux_classes_custom;

	IbmlData *ibml_data;
	IbmlCatagory    *ibml_catagory;
	IbmlElement     *ibml_element;
	IbmlProperty    *ibml_property;
	int i, j, k, n;

	char *id, *scope;
	char *name, *value;

	num_aux_dirs = 0;
	for (dir=aux_dir; dir->name.ptr; dir++) num_aux_dirs++;

	num_aux_classes = 0;
	for (class=xaux_classes; class->classname; class++) num_aux_classes++;

	DEBUG_printf("num_aux_dirs: %d, num_aux_classes: %d\n", num_aux_dirs, num_aux_classes);
	ibml_data = (IbmlData *)imbean_config_new_from_file(aux_dir_config_file);
	if (ibml_data == NULL) return(AUX_FAIL);

	num_aux_classes_custom = 0;
	num_aux_dirs_custom = 0;
	for (k=0; k<ibml_data->num_catagories; k++) {
		ibml_catagory = ibml_data->catagories[k];

		if (ibml_catagory->scope == NULL) continue;
		if (! *ibml_catagory->scope) continue;
		if (strcasecmp(ibml_catagory->scope, "gtk2") && 
		    strcasecmp(ibml_catagory->scope, "qt") &&
		    strcasecmp(ibml_catagory->scope, "binary"))
			continue;

		for (i=0; i<ibml_catagory->num_elements; i++) {
			CARD16 *utfname_ptr;
			char *aux_module_class_name = NULL;
			char *aux_module_object_file = NULL;
			char *aux_module_file_path = NULL;

			ibml_element = ibml_catagory->elements[i];
			if (!ibml_element) continue;

			id = (char *)ibml_element->id;
			scope = (char *)ibml_element->scope;
			DEBUG_printf("id:%s, scope:%s\n", id?id:"NULL", scope?scope:"NULL");
			if (!id || !*id) continue;

			for(j=0; j<ibml_element->num_properties; j++) {
				ibml_property = ibml_element->properties[j];
				if (!ibml_property) continue;

				name = (char *)ibml_property->name;
				if (!name || !*name)
					continue;

				value = (char *)ibml_property->value;
				if (!value || !*value)
					continue;

				if (!strcasecmp(name, AUX_MODULE_CLASS_NAME)) {
					aux_module_class_name = value;
				} else if (!strcasecmp(name, AUX_MODULE_OBJECT_FILE)) {
					aux_module_object_file = value;
				}
			}

			if (!aux_module_class_name || !*aux_module_class_name)
				continue;
			if (!aux_module_object_file || !*aux_module_object_file)
				continue;

			DEBUG_printf("category: %s, classname: %s, object: %s\n",
				ibml_catagory->scope, aux_module_class_name, aux_module_object_file);

			if (num_aux_dirs + num_aux_dirs_custom >= MAX_NUM_AUX_MODULES-1)
				break;

			utfname_ptr = utfname_aux_modules_custom[num_aux_dirs_custom];
			for (n=0; n<strlen(aux_module_class_name); n++) {
				if (n >= MAX_LEN_CLASS_NAME-1) break;
				utfname_ptr[n] = aux_module_class_name[n];
			}
			utfname_ptr[n] = 0;

			dir = &(aux_dir[num_aux_dirs + num_aux_dirs_custom]);
			dir->name.ptr = utfname_ptr;
			dir->name.len = n * sizeof(CARD16);
			dir->method   = &xaux_so_methods;

			num_aux_dirs_custom ++;

			if (strcasecmp(ibml_catagory->scope, "binary"))
				continue;

			aux_module_file_path =  aux_dir_get_full_file_path(aux_module_object_file);
			if (aux_module_file_path == NULL)
				continue;

			strncpy(exec_aux_modules_custom[num_aux_classes_custom],
				aux_module_file_path,
				MAX_LEN_CLASS_NAME-1);
			free((char *)aux_module_file_path);

			class = &(xaux_classes[num_aux_classes + num_aux_classes_custom]);
			strncpy(classname_aux_modules_custom[num_aux_classes_custom],
				aux_module_class_name,
				MAX_LEN_CLASS_NAME-1);
			class->classname = classname_aux_modules_custom[num_aux_classes_custom];
			class->index = 0;
			class->extexec = exec_aux_modules_custom[num_aux_classes_custom];
			class->sowin = 0;
			class->clientwin = 0;
			class->utfname = utfname_ptr;
			
			num_aux_classes_custom ++;
		}
	}

	dir = &(aux_dir[num_aux_dirs + num_aux_dirs_custom]);
	dir->name.ptr = NULL;
	dir->name.len = 0;
	dir->method   = NULL;

	class = &(xaux_classes[num_aux_classes + num_aux_classes_custom]);
	class->classname = NULL;

	ibml_data_free(ibml_data);
	return (AUX_OK);
}

aux_dir_t *aux_dir_init()
{
	char *aux_dir_config_file = NULL;

	aux_dir_config_file =  aux_dir_get_full_file_path(XAUX_MODULES_FILE);

	if (aux_dir_config_file) {
		DEBUG_printf("aux_dir_config_file: %s\n", aux_dir_config_file);
		aux_dir_get_custom_aux_modules(aux_dir_config_file);
		free ((char *)aux_dir_config_file);
	}

#ifdef DEBUG
	aux_dir_print(aux_dir);
	aux_classes_print(xaux_classes);
#endif

	return (aux_dir);
}

#endif
