#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include <iiimp-data.h>

#include "iiimp-dataP.h"


IIIMP_inputmethod_descriptor *
iiimp_inputmethod_descriptor_new(
    IIIMP_data_s *	data_s,
    IIIMP_card16	id,
    IIIMP_string *	idname,
    IIIMP_string *	hrn,
    IIIMP_language *	language,
    IIIMP_string *	rdun)
{
    IIIMP_inputmethod_descriptor *	imd;

    REQUIRE_PROTOCOL_VERSION(data_s, 3);

    imd = (IIIMP_inputmethod_descriptor *)
	malloc(sizeof (IIIMP_inputmethod_descriptor));
    if (NULL == imd) {
	data_s->status = IIIMP_DATA_MALLOC_ERROR;
	return NULL;
    }

    imd->nbyte = (2 + 2);
    imd->id = id;
    imd->next = NULL;

    imd->idname = idname;
    if (NULL == idname) {
	imd->nbyte += 4;
    } else {
	imd->nbyte += idname->nbyte;
    }

    imd->hrn = hrn;
    if (NULL == hrn) {
	imd->nbyte += 4;
    } else {
	imd->nbyte += hrn->nbyte;
    }

    imd->nbyte += 4;
    imd->language_nbyte = 0;
    imd->language = language;
    for (; NULL != language; language = language->next) {
	imd->language_nbyte += language->nbyte;
    }
    imd->nbyte += imd->language_nbyte;

    imd->rdun = rdun;
    if (NULL == rdun) {
	imd->nbyte += 4;
    } else {
	imd->nbyte += rdun->nbyte;
    }

    return imd;
}


void
iiimp_inputmethod_descriptor_delete(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	im_desc)
{
    if (NULL == im_desc) return;
    iiimp_string_delete(data_s, im_desc->idname);
    iiimp_string_delete(data_s, im_desc->hrn);
    iiimp_language_list_delete(data_s, im_desc->language);
    iiimp_string_delete(data_s, im_desc->rdun);
    free(im_desc);
    return;
}


void
iiimp_inputmethod_descriptor_list_delete(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	im_desc)
{
    IIIMP_inputmethod_descriptor *	im_desc_next;
    for (; NULL != im_desc; im_desc = im_desc_next) {
	im_desc_next = im_desc->next;
	iiimp_inputmethod_descriptor_delete(data_s, im_desc);
    }
    return;
}


void
iiimp_inputmethod_descriptor_pack(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	m,
    size_t *				nbyte,
    uchar_t **				ptr)
{
    size_t	rest;
    uchar_t *	p;

    rest = *nbyte;
    p = *ptr;

    PUTU16(m->id, rest, p, data_s->byte_swap);
    PUTU16(0, rest, p, data_s->byte_swap);
    iiimp_string_pack(data_s, m->idname, &rest, &p);
    iiimp_string_pack(data_s, m->hrn, &rest, &p);
    PUT32(m->language_nbyte, rest, p, data_s->byte_swap);
    iiimp_language_list_pack(data_s, m->language, &rest, &p);
    iiimp_string_pack(data_s, m->rdun, &rest, &p);

    *nbyte = rest;
    *ptr = p;

    return;
}


void
iiimp_inputmethod_descriptor_list_pack(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	m,
    size_t *				nbyte,
    uchar_t **				ptr)
{
    size_t	rest;
    uchar_t *	p;

    rest = *nbyte;
    p = *ptr;

    for (; NULL != m; m = m->next) {
	iiimp_inputmethod_descriptor_pack(data_s, m, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_inputmethod_descriptor *
iiimp_inputmethod_descriptor_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    const uchar_t *			p;
    IIIMP_inputmethod_descriptor *	r;
    size_t				rest;
    int					len;

    rest = nbyte_max;
    p = *ptr;

    if ((*nbyte < rest) || (rest < 4)) {
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    r = (IIIMP_inputmethod_descriptor *)
	malloc(sizeof (IIIMP_inputmethod_descriptor));
    if (NULL == r) {
	data_s->status = IIIMP_DATA_MALLOC_ERROR;
	return NULL;
    }

    GETU16(r->id, rest, p, data_s->byte_swap);
    SKIP16(rest, p);
    r->next = NULL;

    r->idname = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == r->idname) {
	iiimp_inputmethod_descriptor_delete(data_s, r);
	return NULL;
    }

    r->hrn = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == r->hrn) {
	iiimp_inputmethod_descriptor_delete(data_s, r);
	return NULL;
    }

    GET32(len, rest, p, data_s->byte_swap);
    if ((len < 0) || (rest < len)) {
	iiimp_inputmethod_descriptor_delete(data_s, r);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    r->language = iiimp_language_list_unpack(data_s, &rest, &p, len);
    if (NULL == r->language) {
	iiimp_inputmethod_descriptor_delete(data_s, r);
	return NULL;
    }

    r->rdun = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == r->rdun) {
	iiimp_inputmethod_descriptor_delete(data_s, r);
	return NULL;
    }

    *nbyte = rest;
    *ptr = p;

    return r;
}


IIIMP_inputmethod_descriptor *
iiimp_inputmethod_descriptor_list_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_inputmethod_descriptor *	im_desc;
    size_t				rest;
    const uchar_t *			p;
    IIIMP_inputmethod_descriptor *	im_desc_first;
    IIIMP_inputmethod_descriptor *	im_desc_last;

    rest = nbyte_max;
    p = *ptr;
    im_desc_first = NULL;
    im_desc_last = NULL;

    if (((*nbyte) < nbyte_max) || (0 != (rest & 0x01))) {
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    while (0 < rest) {
	im_desc = iiimp_inputmethod_descriptor_unpack(data_s, &rest, &p, rest);
	if (NULL == im_desc) {
	    iiimp_inputmethod_descriptor_list_delete(data_s, im_desc_first);
	    return NULL;
	} else {
	    if (NULL == im_desc_first) {
		im_desc_first = im_desc;
	    } else {
		im_desc_last->next = im_desc;
	    }
	    im_desc_last = im_desc;
	}
    }

    *nbyte -= (nbyte_max - rest);
    *ptr = p;

    return im_desc_first;
}


void
iiimp_inputmethod_descriptor_print(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	m)
{
    IIIMP_language *	l;

    if (NULL == m) return;

    (void)fprintf(data_s->print_fp, "\t\tinput method identifier = %d\n",
		  m->id);

    (void)fprintf(data_s->print_fp, "\t\tid name = ");
    iiimp_string_print(data_s, m->idname);
    (void)fputc('\n', data_s->print_fp);

    (void)fprintf(data_s->print_fp, "\t\tname (hrn) = ");
    iiimp_string_print(data_s, m->hrn);
    (void)fputc('\n', data_s->print_fp);

    for (l = m->language; NULL != l; l = l->next) {
	(void)fprintf(data_s->print_fp, "\t\tsupported language=(");
	iiimp_language_print(data_s, l);
	(void)fprintf(data_s->print_fp, ")\n");
    }

    (void)fprintf(data_s->print_fp, "\t\treverse domain name = ");
    iiimp_string_print(data_s, m->rdun);
    (void)fputc('\n', data_s->print_fp);
}


void
iiimp_inputmethod_descriptor_list_print(
    IIIMP_data_s *			data_s,
    IIIMP_inputmethod_descriptor *	m)
{
    for (; NULL != m; m = m->next) {
	iiimp_inputmethod_descriptor_print(data_s, m);
    }
}


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