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

#include <iiimp-data.h>

#include "iiimp-dataP.h"


IIIMP_char_with_feedback *
iiimp_char_with_feedback_new(
    IIIMP_data_s *		data_s,
    IIIMP_card16		code,
    IIIMP_feedback_attr_list *	feedback_attr)
{
    IIIMP_char_with_feedback *	cwf;

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

    cwf->nbyte = (2 + 2 + feedback_attr->nbyte);
    cwf->code = code;
    cwf->feedback_attr = feedback_attr;
    cwf->next = NULL;

    return cwf;
}


void
iiimp_char_with_feedback_delete(
    IIIMP_data_s *		data_s,
    IIIMP_char_with_feedback *	cwf)
{
    if (NULL == cwf) return;
    iiimp_feedback_attr_list_delete(data_s, cwf->feedback_attr);
    free(cwf);
    return;
}


void
iiimp_char_with_feedback_list_delete(
    IIIMP_data_s *		data_s,
    IIIMP_char_with_feedback *	cwf)
{
    IIIMP_char_with_feedback *	cwf_next;
    for (; NULL != cwf; cwf = cwf_next) {
	cwf_next = cwf->next;
	iiimp_char_with_feedback_delete(data_s, cwf);
    }
    return;
}


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

    rest = *nbyte;
    p = *ptr;

    PUTU16(m->code, rest, p, data_s->byte_swap);
    PUTU16(m->feedback_attr->nbyte, rest, p, data_s->byte_swap);
    iiimp_feedback_attr_list_pack(data_s, m->feedback_attr, &rest, &p);

    *nbyte = rest;
    *ptr = p;

    return;
}


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

    rest = *nbyte;
    p = *ptr;

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

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_char_with_feedback *
iiimp_char_with_feedback_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_char_with_feedback *	cwf;
    size_t			rest;
    const uchar_t *		p;
    int				len;

    rest = nbyte_max;
    p = *ptr;

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

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

    GETU16(cwf->code, rest, p, data_s->byte_swap);
    GET16(len, rest, p, data_s->byte_swap);
    if ((len < 0) || (rest < len) || (0 != (len & 0x07))) {
	free(cwf);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    cwf->next = NULL;
    cwf->feedback_attr =
	iiimp_feedback_attr_list_unpack(data_s, &rest, &p, len);
    if (NULL == cwf->feedback_attr) {
	free(cwf);
	return NULL;
    }

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

    return cwf;
}


IIIMP_char_with_feedback *
iiimp_char_with_feedback_list_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_char_with_feedback *	cwf;
    size_t			rest;
    const uchar_t *		p;
    IIIMP_char_with_feedback *	cwf_first;
    IIIMP_char_with_feedback *	cwf_last;

    rest = nbyte_max;
    p = *ptr;
    cwf = NULL;
    cwf_first = NULL;
    cwf_last = NULL;

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

    while (0 < rest) {
	cwf = iiimp_char_with_feedback_unpack(data_s, &rest, &p, rest);
	if (NULL == cwf) {
	    iiimp_char_with_feedback_list_delete(data_s, cwf_first);
	    return NULL;
	} else {
	    if (NULL == cwf_first) {
		cwf_first = cwf;
	    } else {
		cwf_last->next = cwf;
	    }
	    cwf_last = cwf;
	}
    }

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

    return cwf_first;
}


void
iiimp_char_with_feedback_print(
    IIIMP_data_s *		data_s,
    IIIMP_char_with_feedback *	m)
{
    if (NULL == m) return;
    (void)fprintf(data_s->print_fp, "U+%04x", m->code);
    iiimp_feedback_attr_list_print(data_s, m->feedback_attr);
}


void
iiimp_char_with_feedback_list_print(
    IIIMP_data_s *		data_s,
    IIIMP_char_with_feedback *	m)
{
    for (; NULL != m; m = m->next) {
	(void)fputc('\t', data_s->print_fp);
	iiimp_char_with_feedback_print(data_s, m);
	(void)fputc('\n', data_s->print_fp);
    }
}


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