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

#include <iiimp-data.h>

#include "iiimp-dataP.h"


IIIMP_text *
iiimp_text_new(
    IIIMP_data_s *		data_s,
    IIIMP_char_with_feedback *	cwf,
    IIIMP_annotation *		anno)
{
    IIIMP_text *	text;

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

    text->nbyte = 4;

    text->char_with_feedback_nbyte = 0;
    text->char_with_feedback = cwf;
    for (; NULL != cwf; cwf = cwf->next) {
	text->char_with_feedback_nbyte += cwf->nbyte;
    }
    text->nbyte += text->char_with_feedback_nbyte;

    text->nbyte += 4;

    text->annotation_nbyte = 0;
    text->annotation = anno;
    for (; NULL != anno; anno = anno->next) {
	text->annotation_nbyte += anno->nbyte;
    }
    text->nbyte += text->annotation_nbyte;

    text->next = NULL;

    return text;
}


void
iiimp_text_delete(IIIMP_data_s * data_s, IIIMP_text * text)
{
    if (NULL != text) {
	iiimp_char_with_feedback_list_delete(data_s, text->char_with_feedback);
	iiimp_annotation_delete(data_s, text->annotation);
	free(text);
    }
    return;
}


void
iiimp_text_list_delete(IIIMP_data_s * data_s, IIIMP_text * text)
{
    IIIMP_text *	text_cur;
    IIIMP_text *	text_next;
    for (text_cur = text; NULL != text_cur; text_cur = text_next) {
	text_next = text_cur->next;
	iiimp_char_with_feedback_list_delete(data_s,
					     text_cur->char_with_feedback);
	iiimp_annotation_delete(data_s, text_cur->annotation);
	free(text_cur);
    }
    return;
}


void
iiimp_text_pack(
    IIIMP_data_s *	data_s,
    IIIMP_text *	m,
    size_t *		nbyte,
    uchar_t **		ptr)
{
    uchar_t *			p;
    size_t			rest;
    IIIMP_char_with_feedback *	cwf;
    IIIMP_annotation *		anno;
    size_t			n;

    rest = *nbyte;
    p = *ptr;

    n = 0;
    cwf = ((NULL == m) ? NULL : m->char_with_feedback);
    for (; NULL != cwf; cwf = cwf->next) {
	n += cwf->nbyte;
    }
    PUT32(n, rest, p, data_s->byte_swap);
    if (0 < n) {
	iiimp_char_with_feedback_list_pack(data_s, m->char_with_feedback,
					   &rest, &p);
    }

    n = 0;
    anno = ((NULL == m) ? NULL : m->annotation);
    for (; NULL != anno; anno = anno->next) {
	n += anno->nbyte;
    }
    PUT32(n, rest, p, data_s->byte_swap);
    if (0 < n) {
	iiimp_annotation_list_pack(data_s, m->annotation, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


void
iiimp_text_list_pack(
    IIIMP_data_s *	data_s,
    IIIMP_text *	text,
    size_t *		nbyte,
    uchar_t **		ptr)
{
    size_t		rest;
    uchar_t *		p;

    rest = *nbyte;
    p = *ptr;

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

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_text *
iiimp_text_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_text *	text;
    const uchar_t *	p;
    size_t		rest;
    int			data_size;

    rest = nbyte_max;
    p = *ptr;

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

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

    text->char_with_feedback = NULL;
    text->annotation = NULL;
    text->next = NULL;

    GET32(data_size, rest, p, data_s->byte_swap);
    if ((data_size < 0) || (rest < (data_size + 4))) {
	iiimp_text_delete(data_s, text);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    if (0 < data_size) {
	text->char_with_feedback =
	    iiimp_char_with_feedback_list_unpack(data_s, &rest, &p, data_size);
	if ((NULL == text->char_with_feedback) || (rest < 4)) {
	    iiimp_text_delete(data_s, text);
	    return NULL;
	}
    }

    GET32(data_size, rest, p, data_s->byte_swap);
    if ((data_size < 0) || (rest < data_size)) {
	iiimp_text_delete(data_s, text);
	data_s->status = IIIMP_DATA_INVALID;
	return NULL;
    }

    if (0 < data_size) {
	text->annotation =
	    iiimp_annotation_unpack(data_s, &rest, &p, data_size);
	if (NULL == text->annotation) {
	    iiimp_text_delete(data_s, text);
	    return NULL;
	}
    }

    *nbyte = rest;
    *ptr = p;

    return text;
}


IIIMP_text *
iiimp_text_list_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_text *	text;
    size_t		rest;
    const uchar_t *	p;
    IIIMP_text *	text_first;
    IIIMP_text *	text_last;

    rest = nbyte_max;
    p = *ptr;
    text_first = NULL;
    text_last = NULL;

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

    while (0 < rest) {
	text = iiimp_text_unpack(data_s, &rest, &p, rest);
	if (NULL == text) {
	    iiimp_text_list_delete(data_s, text_first);
	    return NULL;
	} else {
	    if (NULL == text_first) {
		text_first = text;
	    } else {
		text_last->next = text;
	    }
	    text_last = text;
	}
    }

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

    return text_first;
}


void
iiimp_text_print(
    IIIMP_data_s *	data_s,
    IIIMP_text *	m)
{
    if (NULL == m) return;
    iiimp_char_with_feedback_list_print(data_s, m->char_with_feedback);
    iiimp_annotation_print(data_s, m->annotation);
}


void
iiimp_text_list_print(
    IIIMP_data_s *	data_s,
    IIIMP_text *	m)
{
    for (; NULL != m; m = m->next) {
	iiimp_text_print(data_s, m);
    }
}


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