#include <stdlib.h>

#include <iiimp.h>

#include "input-method.h"
#include "input-context.h"
#include "handler.h"
#include "stream.h"
#include "role-data-client.h"
#include "role-data-server.h"


IIIMF_status
iiimf_im_new(
    IIIMF_role		role,
    const char *	server_node,
    const char *	service,
    void *		client_data,
    IIIMF_im **		im_ret)
{
    IIIMF_im *		im;
    IIIMF_status	status;
    size_t		size;

    im = (IIIMF_im *)malloc(sizeof (IIIMF_im));
    if (NULL == im) return IIIMF_STATUS_MALLOC;

    im->im_id = -1;

    im->data_s = NULL;

    im->role = role;
    im->state = 0;

    im->message_pending = NULL;
    im->message_depth = 0;
    im->message_depth_maximum = 8;

    im->role_data.client = NULL;
    im->role_data.server = NULL;

    im->message_handler_call = iiimf_message_handler_call;
    im->message_handler = NULL;

    im->ic_list = NULL;

    im->stream = NULL;

    im->client_data = client_data;

    im->data_s = iiimp_data_s_new();
    if (NULL == im->data_s) {
	iiimf_im_delete(im);
	return IIIMF_STATUS_FAIL;
    }

    size = ((sizeof (IIIMF_message_pending)) * im->message_depth_maximum);
    im->message_pending = (IIIMF_message_pending *)malloc(size);
    if (NULL == im->message_pending) {
	iiimf_im_delete(im);
	return IIIMF_STATUS_MALLOC;
    }

    switch (role) {
    case IIIMF_ROLE_CLIENT:
	status = iiimf_role_data_client_new(server_node, service,
					    &(im->role_data.client));
	if (IIIMF_STATUS_SUCCESS != status) {
	    iiimf_im_delete(im);
	    return status;
	}
	break;
    case IIIMF_ROLE_SERVER:
	status = iiimf_role_data_server_new(service, &(im->role_data.server));
	if (IIIMF_STATUS_SUCCESS != status) {
	    iiimf_im_delete(im);
	    return status;
	}
	break;
    default:
	iiimf_im_delete(im);
	return IIIMF_STATUS_ARGUMENT;
    }

    status = iiimf_message_handler_entry_new(&(im->message_handler));
    if (IIIMF_STATUS_SUCCESS != status) {
	iiimf_im_delete(im);
	return status;
    }

    status = iiimf_stream_new(role, &(im->stream));
    if (IIIMF_STATUS_SUCCESS != status) {
	iiimf_im_delete(im);
	return status;
    }

    *im_ret = im;

    return IIIMF_STATUS_SUCCESS;
}


void
iiimf_im_delete(IIIMF_im * im)
{
    IIIMF_ic *	ic;
    IIIMF_ic *	ic_next;

    for (ic = im->ic_list; NULL != ic; ic = ic_next) {
	ic_next = ic->next;
	iiimf_ic_delete(ic);
    }

    switch (im->role) {
    case IIIMF_ROLE_CLIENT:
	iiimf_role_data_client_delete(im->role_data.client);
	break;
    case IIIMF_ROLE_SERVER:
	iiimf_role_data_server_delete(im->role_data.server);
	break;
    }

    iiimf_stream_delete(im->stream);
    iiimf_message_handler_entry_delete(im->message_handler);
    free(im->message_pending);
    iiimp_data_s_delete(im->data_s);

    free(im);
}


void *
iiimf_im_data_get(IIIMF_im * im)
{
    return im->client_data;
}


void *
iiimf_im_data_set(IIIMF_im * im, void * client_data)
{
    void *	p;
    p = im->client_data;
    im->client_data = client_data;
    return p;
}


IIIMP_data_s *
iiimf_im_data_s(IIIMF_im * im)
{
    return im->data_s;
}


IIIMF_status
iiimf_im_stream_proc_set(
    IIIMF_im *			im,
    IIIMF_stream_proc_open	proc_open,
    IIIMF_stream_proc_accept	proc_accept,
    IIIMF_stream_proc_read	proc_read,
    IIIMF_stream_proc_write	proc_write,
    IIIMF_stream_proc_close	proc_close,
    IIIMF_stream_proc_data *	proc_data)
{
    return iiimf_stream_proc_set(im,
				 proc_open, proc_accept, proc_read,
				 proc_write, proc_close, proc_data);
}


IIIMF_status
iiimf_im_fd_set(IIIMF_im * im, int fd)
{
    return iiimf_stream_fd_set(im->stream, fd);
}


IIIMF_status
iiimf_im_timeout_set(IIIMF_im * im, int timeout)
{
    return iiimf_stream_timeout_set(im->stream, timeout);
}


IIIMF_status
iiimf_im_start(IIIMF_im * im)
{
    return im->stream->proc_open(im, im->stream->proc_data);
}


IIIMF_status
iiimf_im_end(IIIMF_im * im)
{
    return im->stream->proc_close(im->stream->proc_data);
}


IIIMF_status
iiimf_im_server_accept(IIIMF_im * im, void * client_data, IIIMF_im ** im_ret)
{
    return im->stream->proc_accept(im, im->stream->proc_data, client_data,
				   im_ret);
}


int
iiimf_im_id(IIIMF_im * im)
{
    return im->im_id;
}


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