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

#include <iiimp-data.h>

#include "iiimp-dataP.h"


IIIMP_client_descriptor *
iiimp_client_descriptor_new(
    IIIMP_data_s *	data_s,
    IIIMP_string *	type,
    IIIMP_string *	os_name,
    IIIMP_string *	arch,
    IIIMP_string *	version,
    IIIMP_string *	X_display_name,
    IIIMP_string *	X_server_vendor)
{
    IIIMP_client_descriptor *	cd;

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

    cd->nbyte = 0;
    if (NULL == type) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += type->nbyte;
    }
    if (NULL == os_name) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += os_name->nbyte;
    }
    if (NULL == arch) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += arch->nbyte;
    }
    if (NULL == version) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += version->nbyte;
    }
    if (NULL == X_display_name) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += X_display_name->nbyte;
    }
    if (NULL == X_server_vendor) {
	cd->nbyte += 4;
    } else {
	cd->nbyte += X_server_vendor->nbyte;
    }
    /*
    if (NULL == X_display_name) {
	if (NULL != X_server_vendor) {
	    cd->nbyte += 4;
	}
    } else {
	cd->nbyte += X_display_name->nbyte;
    }
    if (NULL == X_server_vendor) {
	if (NULL != X_display_name) {
	    cd->nbyte += 4;
	}
    } else {
	cd->nbyte += X_server_vendor->nbyte;
    }
    */

    cd->type = type;
    cd->os_name = os_name;
    cd->arch = arch;
    cd->version = version;
    cd->X_display_name = X_display_name;
    cd->X_server_vendor = X_server_vendor;

    return cd;
}


void
iiimp_client_descriptor_delete(
    IIIMP_data_s *		data_s,
    IIIMP_client_descriptor *	cd)
{
    if (NULL == cd) return;
    iiimp_string_delete(data_s, cd->type);
    iiimp_string_delete(data_s, cd->os_name);
    iiimp_string_delete(data_s, cd->arch);
    iiimp_string_delete(data_s, cd->version);
    iiimp_string_delete(data_s, cd->X_display_name);
    iiimp_string_delete(data_s, cd->X_server_vendor);
    free(cd);
    return;
}


void
iiimp_client_descriptor_pack(
    IIIMP_data_s *		data_s,
    IIIMP_client_descriptor *	cd,
    size_t *			nbyte,
    uchar_t **			ptr)
{
    size_t	rest;
    uchar_t *	p;

    rest = *nbyte;
    p = *ptr;

    iiimp_string_pack(data_s, cd->type, &rest, &p);
    iiimp_string_pack(data_s, cd->os_name, &rest, &p);
    iiimp_string_pack(data_s, cd->arch, &rest, &p);
    iiimp_string_pack(data_s, cd->version, &rest, &p);

    if (NULL != cd->X_display_name) {
	iiimp_string_pack(data_s, cd->X_display_name, &rest, &p);
    }
    if (NULL != cd->X_server_vendor) {
	iiimp_string_pack(data_s, cd->X_server_vendor, &rest, &p);
    }

    *nbyte = rest;
    *ptr = p;

    return;
}


IIIMP_client_descriptor *
iiimp_client_descriptor_unpack(
    IIIMP_data_s *	data_s,
    size_t *		nbyte,
    const uchar_t **	ptr,
    size_t		nbyte_max)
{
    IIIMP_client_descriptor *	cd;
    size_t			rest;
    const uchar_t *		p;

    rest = nbyte_max;
    p = *ptr;

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

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

    cd->type = NULL;
    cd->os_name = NULL;
    cd->arch = NULL;
    cd->version = NULL;
    cd->X_display_name = NULL;
    cd->X_server_vendor = NULL;

    cd->type = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == cd->type) {
	iiimp_client_descriptor_delete(data_s, cd);
	return NULL;
    }
    cd->os_name = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == cd->os_name) {
	iiimp_client_descriptor_delete(data_s, cd);
	return NULL;
    }
    cd->arch = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == cd->arch) {
	iiimp_client_descriptor_delete(data_s, cd);
	return NULL;
    }
    cd->version = iiimp_string_unpack(data_s, &rest, &p, rest);
    if (NULL == cd->version) {
	iiimp_client_descriptor_delete(data_s, cd);
	return NULL;
    }
    if (0 < rest) {
	cd->X_display_name = iiimp_string_unpack(data_s, &rest, &p, rest);
	if (NULL == cd->X_display_name) {
	    iiimp_client_descriptor_delete(data_s, cd);
	    return NULL;
	}
    }
    if (0 < rest) {
	cd->X_server_vendor = iiimp_string_unpack(data_s, &rest, &p, rest);
	if (NULL == cd->X_server_vendor) {
	    iiimp_client_descriptor_delete(data_s, cd);
	    return NULL;
	}
    }

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

    return cd;
}


void
iiimp_client_descriptor_print(
    IIIMP_data_s *		data_s,
    IIIMP_client_descriptor *	m)
{
    if (NULL == m) return;

    (void)fprintf(data_s->print_fp, "\tApplication type=");
    iiimp_string_print(data_s, m->type);
    (void)fputc('\n', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "\tOperating system name=");
    iiimp_string_print(data_s, m->os_name);
    (void)fputc('\n', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "\tOperating system architecture=");
    iiimp_string_print(data_s, m->arch);
    (void)fputc('\n', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "\tOperating system version=");
    iiimp_string_print(data_s, m->version);
    (void)fputc('\n', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "\tX Display Name=");
    iiimp_string_print(data_s, m->X_display_name);
    (void)fputc('\n', data_s->print_fp);
    (void)fprintf(data_s->print_fp, "\tX Server Vendor=");
    iiimp_string_print(data_s, m->X_server_vendor);
    (void)fputc('\n', data_s->print_fp);
}


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