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

#include <iiimp-data.h>

#include "iiimp-dataP.h"


static IIIMP_contents *
iiimp_contents_new(
    IIIMP_data_s *	data_s,
    IIIMP_card32	type,
    void *		value)
{
    IIIMP_contents *	c;

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

    c->nbyte = 4;

    c->type = type;

    c->value.string = NULL;
    c->value.text = NULL;
    c->value.keyevent_list = NULL;

    c->value.any = value;

    switch (type) {
    case IIIMP_CONTENTS_STRING:	/* string */
	c->nbyte += c->value.string->nbyte;
	c->value_nbyte = c->value.string->nbyte;
	break;
    case IIIMP_CONTENTS_TEXT: /* text */
	c->nbyte += c->value.text->nbyte;
	c->value_nbyte = c->value.text->nbyte;
	break;
    case IIIMP_CONTENTS_KEYEVENT: /* keyevent */
	c->nbyte += 4;
	c->nbyte += c->value.keyevent_list->nbyte;
	c->value_nbyte = c->value.keyevent_list->nbyte;
	break;
    default: /* error */
	free(c);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    return c;
}


void
iiimp_contents_delete(IIIMP_data_s * data_s, IIIMP_contents * c)
{
    if (NULL == c) return;

    switch (c->type) {
    case IIIMP_CONTENTS_STRING:	/* string */
	iiimp_string_delete(data_s, c->value.string);
	break;
    case IIIMP_CONTENTS_TEXT: /* text */
	iiimp_text_delete(data_s, c->value.text);
	break;
    case IIIMP_CONTENTS_KEYEVENT: /* keyevent */
	iiimp_keyevent_list_delete(data_s, c->value.keyevent_list);
	break;
    }

    free(c);
}


IIIMP_contents *
iiimp_contents_string_new(
    IIIMP_data_s *	data_s,
    IIIMP_string *	value)
{
    return iiimp_contents_new(data_s, IIIMP_CONTENTS_STRING, (void *)value);
}


IIIMP_contents *
iiimp_contents_text_new(
    IIIMP_data_s *	data_s,
    IIIMP_text *	value)
{
    return iiimp_contents_new(data_s, IIIMP_CONTENTS_TEXT, (void *)value);
}


IIIMP_contents *
iiimp_contents_keyevent_list_new(
    IIIMP_data_s *		data_s,
    IIIMP_keyevent_list *	value)
{
    return iiimp_contents_new(data_s, IIIMP_CONTENTS_KEYEVENT, (void *)value);
}


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

    rest = *nbyte;
    p = *ptr;

    PUTU32(m->type, rest, p, data_s->byte_swap);
    switch (m->type) {
    case IIIMP_CONTENTS_STRING:	/* string */
	iiimp_string_pack(data_s, m->value.string, &rest, &p);
	break;
    case IIIMP_CONTENTS_TEXT: /* text */
	iiimp_text_pack(data_s, m->value.text, &rest, &p);
	break;
    case IIIMP_CONTENTS_KEYEVENT: /* keyevent */
	PUTU32(m->value.keyevent_list->nbyte, rest, p, data_s->byte_swap);
	iiimp_keyevent_list_pack(data_s, m->value.keyevent_list, &rest, &p);
	break;
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_contents *
iiimp_contents_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_contents *	c;
    size_t		rest;
    const uchar_t *	p;
    size_t		n;

    rest = nbyte_max;
    p = *ptr;

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

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

    GETU32(c->type, rest, p, data_s->byte_swap);
    c->value.string = NULL;
    c->value.text = NULL;
    c->value.keyevent_list = NULL;

    switch (c->type) {
    case IIIMP_CONTENTS_STRING:	/* string */
	c->value.string = iiimp_string_unpack(data_s, &rest, &p, rest);
	if (NULL == c->value.string) {
	    free(c);
	    return NULL;
	}
	break;
    case IIIMP_CONTENTS_TEXT: /* text */
	c->value.text = iiimp_text_unpack(data_s, &rest, &p, rest);
	if (NULL == c->value.text) {
	    free(c);
	    return NULL;
	}
	break;
    case IIIMP_CONTENTS_KEYEVENT: /* keyevent */
	GETU32(n, rest, p, data_s->byte_swap);
	c->value.keyevent_list =
	    iiimp_keyevent_list_unpack(data_s, &rest, &p, n);
	if (NULL == c->value.keyevent_list) {
	    free(c);
	    return NULL;
	}
	break;
    default: /* error */
	free(c);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    *nbyte = rest;
    *ptr = p;

    return c;
}


void
iiimp_contents_print(
    IIIMP_data_s *	data_s,
    IIIMP_contents *	m)
{
    if (NULL == m) return;

    switch (m->type) {
    case IIIMP_CONTENTS_STRING: /* string */
	(void)fprintf(data_s->print_fp, "\t*");
	iiimp_string_print(data_s, m->value.string);
	(void)fputc('\n', data_s->print_fp);
	break;
    case IIIMP_CONTENTS_TEXT: /* text */
	iiimp_text_print(data_s, m->value.text);
	break;
    case IIIMP_CONTENTS_KEYEVENT: /* keyevent */
	iiimp_keyevent_list_print(data_s, m->value.keyevent_list);
	break;
    }
}


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