#include <ncbi.h>
#include <gishlib.h>


void LIBCALL
AnyDataAssign(any, usertype, datatype, valueptr, valuelen)
	AnyDataPtr	any;
	int			usertype;
	AnyType		datatype;
	Nlm_VoidPtr		valueptr;
	size_t		valuelen;
{
	any->usertype = usertype;
	any->type = datatype;
	any->stdalloc = FALSE;
	switch (datatype) {
	case ANY_CHAR:
		any->value.c = *(CharPtr)valueptr;
		break;
	case ANY_UCHAR:
		any->value.uc = *(UcharPtr)valueptr;
		break;
	case ANY_SHORT:
		any->value.s = *(short PNTR)valueptr;
		break;
	case ANY_USHORT:
		any->value.us = *(unsigned short PNTR)valueptr;
		break;
	case ANY_INT:
		any->value.i = *(int PNTR)valueptr;
		break;
	case ANY_UINT:
		any->value.u = *(unsigned PNTR)valueptr;
		break;
	case ANY_LONG:
		any->value.l = *(long PNTR)valueptr;
		break;
	case ANY_ULONG:
		any->value.ul = *(unsigned long PNTR)valueptr;
		break;
	case ANY_FLOAT:
		any->value.f = *(float PNTR)valueptr;
		break;
	case ANY_DOUBLE:
		any->value.d = *(double PNTR)valueptr;
		break;
	case ANY_CHARPTR:
		any->value.cp = (CharPtr)valueptr;
		break;
	case ANY_CSTR:
		any->value.cstr = (CharPtr)valueptr;
		break;
	case ANY_VOIDPTR:
		any->value.vp = (VoidPtr)valueptr;
		break;
	case ANY_BUFFER:
		any->value.buf.len = valuelen;
		any->value.buf.ptr = valueptr;
		break;
	default:
		break;
	}
}

AnyDataPtr LIBCALL
AnyDataSave(usertype, datatype, valueptr, valuelen)
	int			usertype;
	AnyType		datatype;
	VoidPtr		valueptr;
	size_t		valuelen;
{
	AnyDataPtr	any;

	any = Nlm_Calloc(1, sizeof(*any));
	if (any == NULL)
		return NULL;

	any->usertype = usertype;
	any->type = datatype;
	any->stdalloc = FALSE;
	switch (datatype) {
	case ANY_CHAR:
		any->value.c = *(CharPtr)valueptr;
		break;
	case ANY_UCHAR:
		any->value.uc = *(UcharPtr)valueptr;
		break;
	case ANY_SHORT:
		any->value.s = *(short PNTR)valueptr;
		break;
	case ANY_USHORT:
		any->value.us = *(unsigned short PNTR)valueptr;
		break;
	case ANY_INT:
		any->value.i = *(int PNTR)valueptr;
		break;
	case ANY_UINT:
		any->value.u = *(unsigned PNTR)valueptr;
		break;
	case ANY_LONG:
		any->value.l = *(long PNTR)valueptr;
		break;
	case ANY_ULONG:
		any->value.ul = *(unsigned long PNTR)valueptr;
		break;
	case ANY_FLOAT:
		any->value.f = *(float PNTR)valueptr;
		break;
	case ANY_DOUBLE:
		any->value.d = *(double PNTR)valueptr;
		break;
	case ANY_CHARPTR:
		any->value.cp = (CharPtr)valueptr;
		break;
	case ANY_CSTR:
		any->value.cstr = (CharPtr)valueptr;
		break;
	case ANY_VOIDPTR:
		any->value.vp = (VoidPtr)valueptr;
		break;
	case ANY_BUFFER:
		any->value.buf.len = valuelen;
		any->value.buf.ptr = valueptr;
		break;
	default:
		Nlm_Free(any);
		return NULL;
	}
	return any;
}

int LIBCALL
AnyDataCmp(any1, any2)
	AnyDataPtr	any1, any2;
{
	if (any1->type != any2->type) {
		if (any1->type > any2->type)
			return 1;
		return -1;
	}
	switch (any1->type) {
	case ANY_CHAR:
		return any1->value.c - any2->value.c;
	case ANY_UCHAR:
		if (any1->value.uc > any2->value.uc)
			return 1;
		if (any1->value.uc < any2->value.uc)
			return -1;
		return 0;
	case ANY_SHORT:
		if (any1->value.s > any2->value.s)
			return 1;
		if (any1->value.s < any2->value.s)
			return -1;
		return 0;
	case ANY_USHORT:
		if (any1->value.us > any2->value.us)
			return 1;
		if (any1->value.us < any2->value.us)
			return -1;
		return 0;
	case ANY_INT:
		return any1->value.i - any2->value.i;
	case ANY_UINT:
		if (any1->value.u > any2->value.u)
			return 1;
		if (any1->value.u < any2->value.u)
			return -1;
		return 0;
	case ANY_LONG:
		if (any1->value.l > any2->value.l)
			return 1;
		if (any1->value.l < any2->value.l)
			return -1;
		return 0;
	case ANY_ULONG:
		if (any1->value.ul > any2->value.ul)
			return 1;
		if (any1->value.ul < any2->value.ul)
			return -1;
		return 0;
	case ANY_FLOAT:
		if (any1->value.f > any2->value.f)
			return 1;
		if (any1->value.f < any2->value.f)
			return -1;
		return 0;
	case ANY_DOUBLE:
		if (any1->value.d > any2->value.d)
			return 1;
		if (any1->value.d < any2->value.d)
			return -1;
		return 0;
	case ANY_CHARPTR:
		if (any1->value.cp > any2->value.cp)
			return 1;
		if (any1->value.cp < any2->value.cp)
			return -1;
		return 0;
	case ANY_VOIDPTR:
		if (any1->value.vp > any2->value.vp)
			return 1;
		if (any1->value.vp < any2->value.vp)
			return -1;
		return 0;
	case ANY_CSTR:
		return strcmp(any1->value.cstr, any2->value.cstr);
	case ANY_BUFFER:
		{
			int	i; size_t	len;

			len = MIN(any1->value.buf.len, any2->value.buf.len);
			i = memcmp(any1->value.buf.ptr, any2->value.buf.ptr, len);
			if (i != 0)
				return i;
			if (any1->value.buf.len < any2->value.buf.len)
				return -1;
			if (any1->value.buf.len > any2->value.buf.len)
				return 1;
			return 0;
		}
	default:
		if (any1 > any2)
			return 1;
		if (any1 < any2)
			return -1;
		return 0;
	}
	/*NOTREACHED*/
}

void LIBCALL
AnyDataFree(any)
	AnyDataPtr	any;
{
	VoidPtr	vp;

	if (any == NULL)
		return;
	switch (any->type) {
	default:
	case ANY_CHAR:
	case ANY_UCHAR:
	case ANY_SHORT:
	case ANY_USHORT:
	case ANY_INT:
	case ANY_UINT:
	case ANY_LONG:
	case ANY_ULONG:
	case ANY_FLOAT:
	case ANY_DOUBLE:
		vp = NULL;
		break;
	case ANY_CHARPTR:
		vp = any->value.cp;
		any->value.cp = NULL;
		break;
	case ANY_CSTR:
		vp = any->value.cstr;
		any->value.cstr = NULL;
		break;
	case ANY_VOIDPTR:
		vp = any->value.vp;
		any->value.vp = NULL;
		break;
	case ANY_BUFFER:
		vp = any->value.buf.ptr;
		any->value.buf.ptr = NULL;
		break;
	}
	if (vp != NULL)
		Nlm_Free(vp);
	AnyDataDestruct(any->next);
}

void LIBCALL
AnyDataDestruct(any)
	AnyDataPtr	any;
{
	if (any == NULL)
		return;
	AnyDataFree(any);
	Nlm_Free(any);
}

AnyDataPtr LIBCALL
AnyDataAppend(head, newdata)
	AnyDataPtr	head, newdata;
{
	register AnyDataPtr	any;

	if (head == NULL)
		return newdata;

	for (any = head; any->next != NULL; any = any->next)
		;
	any->next = newdata;
	return head;
}
