/*
  component.c
*/

#include <stdlib.h>
#include <string.h>
#include "iiimcfint.h"

/********************************************************************************
			     Predefined Component
********************************************************************************/

static IIIMF_status
iiimcf_component_UI(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_UI)
	&& (type < IIIMCF_EVENT_TYPE_UI_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_UI_preedit(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_UI_PREEDIT)
	&& (type < IIIMCF_EVENT_TYPE_UI_PREEDIT_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_UI_status(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_UI_STATUS)
	&& (type < IIIMCF_EVENT_TYPE_UI_STATUS_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_UI_lookup_choice(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE)
	&& (type < IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_UI_commit(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_UI_COMMIT)
	&& (type < IIIMCF_EVENT_TYPE_UI_COMMIT_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_event(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if (st != IIIMF_STATUS_SUCCESS) return st;
	
    if ((type >= IIIMCF_EVENT_TYPE_EVENTLIKE)
	&& (type < IIIMCF_EVENT_TYPE_EVENTLIKE_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_event_key(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if ((type >= IIIMCF_EVENT_TYPE_KEYEVENT)
	&& (type < IIIMCF_EVENT_TYPE_KEYEVENT_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_event_trigger_notify(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if ((type >= IIIMCF_EVENT_TYPE_TRIGGER_NOTIFY)
	&& (type < IIIMCF_EVENT_TYPE_TRIGGER_NOTIFY_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

static IIIMF_status
iiimcf_component_AUX(
    IIIMCF_context context,
    IIIMCF_event event,
    IIIMCF_component current,
    IIIMCF_component parent
)
{
    IIIMF_status st;
    IIIMCF_event_type type;

    st = iiimcf_get_event_type(event, &type);
    if ((type >= IIIMCF_EVENT_TYPE_AUX)
	&& (type < IIIMCF_EVENT_TYPE_AUX_END))
	return iiimcf_dispatch_event(context, event);

    return IIIMF_STATUS_COMPONENT_INDIFFERENT;
}

/********************************************************************************
			      Internal functions.
********************************************************************************/

static IIIMCF_component_rec*
lookup_component(
    const char *name,
    IIIMCF_component_rec *pc
)
{
    IIIMCF_component_rec *pc2;

    for (; pc; pc = pc->pnext) {
	if (strcmp(pc->name, name) == 0) return pc;
	pc2 = lookup_component(name, pc->pchild);
	if (pc2) return pc2;
    }

    return NULL;
}

typedef struct IIIMCF_component_tree IIIMCF_component_tree;
struct IIIMCF_component_tree {
    char *name;
    IIIMCF_component_interface pint;
    IIIMCF_component_tree *pdec;
};
static IIIMCF_component_tree predefined_root[];
static IIIMCF_component_tree predefined_UI[];
static IIIMCF_component_tree predefined_event[];

static IIIMCF_component_tree predefined_root[] = {
	{"org.OpenI18N.IIIMCF.UI", iiimcf_component_UI, predefined_UI},
	{"org.OpenI18N.IIIMCF.event", iiimcf_component_event, predefined_event},
	{"org.OpenI18N.IIIMCF.AUX", iiimcf_component_AUX, NULL},
	{NULL, NULL, NULL}
};
static IIIMCF_component_tree predefined_UI[] = {
	{"org.OpenI18N.IIIMCF.UI.preedit", iiimcf_component_UI_preedit, NULL},
	{"org.OpenI18N.IIIMCF.UI.status", iiimcf_component_UI_status, NULL},
	{"org.OpenI18N.IIIMCF.UI.lookup_choice", iiimcf_component_UI_lookup_choice, NULL},
	{NULL, NULL, NULL}
};
static IIIMCF_component_tree predefined_event[] = {
	{"org.OpenI18N.IIIMCF.event.key", iiimcf_component_event_key, NULL},
	{"org.OpenI18N.IIIMCF.event.trigger_notify", iiimcf_component_event_trigger_notify, NULL},
	{NULL, NULL, NULL}
};

static IIIMF_status
register_component_tree(
    IIIMCF_handle_rec *ph,
    IIIMCF_component parent_comp,
    IIIMCF_component_tree *pt
)
{
    IIIMF_status st;
    IIIMCF_component comp;

    for (; pt->name; pt++) {
	st = iiimcf_register_component((IIIMCF_handle) ph,
				       pt->name,
				       pt->pint,
				       parent_comp,
				       &comp);
	if (st != IIIMF_STATUS_SUCCESS) return st;
	if (pt->pdec) {
	    st = register_component_tree(ph, comp, pt->pdec);
	    if (st != IIIMF_STATUS_SUCCESS) return st;
	}
    }

    return IIIMF_STATUS_SUCCESS;
}

IIIMF_status
iiimcf_register_predefined_components(
    IIIMCF_handle_rec *ph
)
{
    return register_component_tree(ph, IIIMCF_ROOT_COMPONENT, predefined_root);
}

void
iiimcf_delete_all_components(
    IIIMCF_handle_rec *ph
)
{
    IIIMCF_component_rec *pcom, *pcom2;

    pcom = ph->proot_component;
    while (pcom) {
	pcom2 = pcom->pnext;
	iiimcf_unregister_component(pcom);
	pcom = pcom2;
    }
    ph->proot_component = NULL;
}

/********************************************************************************
			            APIs
********************************************************************************/

IIIMF_status
iiimcf_register_component(
    IIIMCF_handle handle,
    const char* name,
    IIIMCF_component_interface interface,
    IIIMCF_component parent,
    IIIMCF_component* pcomp
)
{
    IIIMCF_handle_rec *ph = (IIIMCF_handle_rec*) handle;
    IIIMCF_component_rec *pcom_parent = (IIIMCF_component_rec*) parent;
    IIIMCF_component_rec *pc;

    pc = lookup_component(name, ph->proot_component);
    if (pc) return IIIMF_STATUS_COMPONENT_DUPLICATED_NAME;

    pc = (IIIMCF_component_rec*) malloc(sizeof(*pc));
    if (!pc) return IIIMF_STATUS_MALLOC;
    memset(pc, 0, sizeof(*pc));
    pc->name = strdup(name);
    if (!pc->name) {
	free(pc);
	return IIIMF_STATUS_MALLOC;
    }

    pc->ph = ph;
    pc->func = interface;
    pc->pparent = pcom_parent;
    if (pcom_parent) {
	pc->pnext = pcom_parent->pchild;
	pcom_parent->pchild = pc;
    } else {
	pc->pnext = ph->proot_component;
	ph->proot_component = pc;
    }
    if (pc->pnext) {
	pc->pnext->pprev = pc;
    }

    *pcomp = pc;

    return IIIMF_STATUS_SUCCESS;
}

IIIMF_status
iiimcf_unregister_component(
    IIIMCF_component component
)
{
    IIIMCF_component_rec *pc = (IIIMCF_component_rec*) component;
    IIIMCF_component_rec *pc2, *pc3;

    for (pc2 = pc->pchild; pc2; ) {
	pc3 = pc2->pnext;
	if (pc2->pchild) {
	    iiimcf_unregister_component(pc2);
	} else {
	    free(pc2->name);
	    if (pc2->attr) iiimcf_destroy_attr(pc2->attr);
	    free(pc2);
	}
	pc2 = pc3;
    }
    if (pc->attr) iiimcf_destroy_attr(pc->attr);
    if (pc->pprev) {
	pc->pprev->pnext = pc->pnext;
    }
    if (pc->pnext) {
	pc->pnext->pprev = pc->pprev;
    }

    free(pc->name);
    free(pc);

    return IIIMF_STATUS_SUCCESS;
}

IIIMF_status
iiimcf_get_component(
    IIIMCF_handle handle,
    const char *name,
    IIIMCF_component* pcomponent
)
{
    IIIMCF_handle_rec *ph = (IIIMCF_handle_rec*) handle;
    IIIMCF_component_rec *pc = ph->proot_component;

    pc = lookup_component(name, pc);
    if (!pc) return IIIMF_STATUS_COMPONENT_DUPLICATED_NAME;

    *pcomponent = pc;

    return IIIMF_STATUS_SUCCESS;
}

IIIMF_status
iiimcf_component_get_attr(
    IIIMCF_component component,
    IIIMCF_attr* pattr
)
{
    IIIMF_status st;
    IIIMCF_component_rec *pc = (IIIMCF_component_rec*) component;

    if (pc->attr) {
	*pattr = pc->attr;
	return IIIMF_STATUS_SUCCESS;
    }
    st = iiimcf_create_attr(pattr);
    if (st != IIIMF_STATUS_SUCCESS) return st;
    pc->attr = *pattr;

    return IIIMF_STATUS_SUCCESS;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */

