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

#include <iiimp-data.h>

#include "iiimp-dataP.h"


static IIIMP_icattribute *
iiimp_icattribute_new(
    IIIMP_data_s *	data_s,
    IIIMP_card16	id,
    void *		value,
    IIIMP_card16	input_method)
{
    IIIMP_icattribute *	attr;

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

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

    switch(id) {
    case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE: /* Input Language */
	attr->value.input_language = value;
	attr->value_nbyte = attr->value.input_language->nbyte;
	break;
    case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS: /* Character Subsets */
	attr->value.character_subsets = value;
	attr->value_nbyte = attr->value.character_subsets->nbyte;
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME: /* Input Mehtod Name */
	attr->value.input_method_name = value;
	attr->value_nbyte = attr->value.input_method_name->nbyte;
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD: /* Input Mehtod */
	attr->value.input_method = input_method;
	attr->value_nbyte = 2;
	break;
    default:
	break;
    }

    attr->nbyte += (attr->value_nbyte + PAD(attr->value_nbyte));

    return attr;
}


void
iiimp_icattribute_delete(IIIMP_data_s * data_s, IIIMP_icattribute * icattr)
{
    if (NULL == icattr) return;

    switch(icattr->id) {
    case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE: /* Input Language */
	iiimp_string_delete(data_s, icattr->value.input_language);
	break;
    case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS: /* Character Subsets */
	iiimp_card32_list_delete(data_s, icattr->value.character_subsets);
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME: /* Input Mehtod Name */
	iiimp_string_delete(data_s, icattr->value.input_method_name);
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD: /* Input Mehtod */
	break;
    default:
	break;
    }
    free(icattr);

    return;
}


void
iiimp_icattribute_list_delete(IIIMP_data_s * data_s, IIIMP_icattribute * icattr)
{
    IIIMP_icattribute *	icattr_next;
    for (; NULL != icattr; icattr = icattr_next) {
	icattr_next = icattr->next;

	switch(icattr->id) {
	case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE:
	    iiimp_string_delete(data_s, icattr->value.input_language);
	    break;
	case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS:
	    iiimp_card32_list_delete(data_s, icattr->value.character_subsets);
	    break;
	case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME:
	    iiimp_string_delete(data_s, icattr->value.input_method_name);
	    break;
	case IIIMP_ICATTRIBUTE_INPUT_METHOD:
	    /* nothing to do */
	    break;
	default:
	    break;
	}
	free(icattr);
    }
    return;
}


IIIMP_icattribute *
iiimp_icattribute_input_language_new(
    IIIMP_data_s *	data_s,
    IIIMP_string *	value)
{
    return iiimp_icattribute_new(data_s, IIIMP_ICATTRIBUTE_INPUT_LANGUAGE,
				 (void *)value, 0);
}


IIIMP_icattribute *
iiimp_icattribute_character_subsets_new(
    IIIMP_data_s *	data_s,
    IIIMP_card32_list *	value)
{
    return iiimp_icattribute_new(data_s, IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS,
				 (void *)value, 0);
}


IIIMP_icattribute *
iiimp_icattribute_input_method_name_new(
    IIIMP_data_s *	data_s,
    IIIMP_string *	value)
{
    return iiimp_icattribute_new(data_s, IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME,
				 (void *)value, 0);
}


IIIMP_icattribute *
iiimp_icattribute_input_method_new(
    IIIMP_data_s *	data_s,
    IIIMP_card16	value)
{
    return iiimp_icattribute_new(data_s, IIIMP_ICATTRIBUTE_INPUT_METHOD,
				 NULL, value);
}


void
iiimp_icattribute_pack(
    IIIMP_data_s *	data_s,
    IIIMP_icattribute *	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(m->value_nbyte, rest, p, data_s->byte_swap);

    switch(m->id) {
    case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE: /* Input Language */
	iiimp_string_pack(data_s, m->value.input_language, &rest, &p);
	break;
    case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS: /* Character Subsets */
	iiimp_card32_list_pack(data_s, m->value.character_subsets, &rest, &p);
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME: /* Input Mehtod Name */
	iiimp_string_pack(data_s, m->value.input_method_name, &rest, &p);
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD: /* Input Mehtod */
	PUTU16(m->value.input_method, rest, p, data_s->byte_swap);
	PUTU16(0, rest, p, data_s->byte_swap);
	break;
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


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

    rest = *nbyte;
    p = *ptr;

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

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_icattribute *
iiimp_icattribute_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_icattribute *	icattr;
    size_t		rest;
    const uchar_t *	p;
    IIIMP_card16	id;
    int			len;

    rest = nbyte_max;
    p = *ptr;

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

    GETU16(id, rest, p, data_s->byte_swap);
    GETU16(len, rest, p, data_s->byte_swap);
    if (0 == len) {
	data_s->status = IIIMP_DATA_NO_ERROR;
	return NULL;
    }
    if ((len < 0) || (rest < len)) {
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

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

    icattr->value_nbyte = len;
    icattr->next = NULL;

    switch(id) {
    case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE: /* Input Language */
	icattr->value.input_language =
	    iiimp_string_unpack(data_s, &rest, &p, len);
	if (NULL == icattr->value.input_language) {
	    iiimp_icattribute_delete(data_s, icattr);
	    return NULL;
	}
	break;
    case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS: /* Character Subsets */
	if (0 < len) {
	    icattr->value.character_subsets =
		iiimp_card32_list_unpack(data_s, &rest, &p, len);
	    if (NULL == icattr->value.character_subsets) {
		iiimp_icattribute_delete(data_s, icattr);
		return NULL;
	    }
	} else {
	    icattr->value.character_subsets = NULL;
	}
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME: /* Input Mehtod Name */
	icattr->value.input_method_name =
	    iiimp_string_unpack(data_s, &rest, &p, len);
	if (NULL == icattr->value.input_method_name) {
	    iiimp_icattribute_delete(data_s, icattr);
	    return NULL;
	}
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD: /* Input Mehtod */
	GETU16(icattr->value.input_method, rest, p, data_s->byte_swap);
	SKIP16(rest, p);
	break;
    default:
	break;
    }

    icattr->id = id;

    *nbyte = rest;
    *ptr = p;

    return icattr;
}


IIIMP_icattribute *
iiimp_icattribute_list_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_icattribute *	attr;
    size_t		rest;
    const uchar_t *	p;
    IIIMP_icattribute *	attr_first;
    IIIMP_icattribute *	attr_last;

    rest = nbyte_max;
    p = *ptr;
    attr_first = NULL;
    attr_last = NULL;

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

    while (0 < rest) {
	attr = iiimp_icattribute_unpack(data_s, &rest, &p, rest);
	if (NULL == attr) {
	    iiimp_icattribute_list_delete(data_s, attr_first);
	    return NULL;
	} else {
	    if (NULL == attr_first) {
		attr_first = attr;
	    } else {
		attr_last->next = attr;
	    }
	    attr_last = attr;
	}
    }

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

    return attr_first;
}
void
iiimp_icattribute_print(
    IIIMP_data_s *	data_s,
    IIIMP_icattribute *	m)
{
    if (NULL == m) return;

    switch (m->id) {
    case IIIMP_ICATTRIBUTE_INPUT_LANGUAGE:	/* Input Language */
	(void)fprintf(data_s->print_fp, "\tInput Language=");
	iiimp_string_print(data_s, m->value.input_language);
	(void)fputc('\n', data_s->print_fp);
	break;
    case IIIMP_ICATTRIBUTE_CHARACTER_SUBSETS:	/* Character Subsets */
	(void)fprintf(data_s->print_fp, "\tcharacter subsets=(");
	iiimp_character_subsets_list_print(data_s, m->value.character_subsets);
	(void)fprintf(data_s->print_fp, ")\n");
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD_NAME:	/* Input Method Name */
	(void)fprintf(data_s->print_fp, "\tInput Method=");
	iiimp_string_print(data_s, m->value.input_language);
	(void)fputc('\n', data_s->print_fp);
	break;
    case IIIMP_ICATTRIBUTE_INPUT_METHOD:	/* Input Method */
	(void)fprintf(data_s->print_fp, "\tInput Method=%d",
		      m->value.input_method);
	(void)fputc('\n', data_s->print_fp);
	break;
    }
}


void
iiimp_icattribute_list_print(
    IIIMP_data_s *	data_s,
    IIIMP_icattribute *	m)
{
    for (; NULL != m; m = m->next) {
	iiimp_icattribute_print(data_s, m);
    }
}


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