/*****
 NAME
 	fxml.h - header file for functions for libxml2
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/fxml.h>
#include <coconut/cxmlnode.h>
#include <coconut/cmemalloc.h>
#include <coconut/csystem.h>
#include <coconut/dbasic.h>
#include <string.h>

typedef enum {
	extxml_unknown,
	extxml_node
} extxml_t ;

typedef struct {
	extxml_t	ext_type ;
} extxmlhead_t ;

typedef struct {
	id <PXMLNode>	xml_node ;
} extxmlinfo_t ;

static const size_t HEADSIZE = ALIGNED_SIZE(sizeof(extxmlhead_t)) ;
static const size_t INFOSIZE = ALIGNED_SIZE(sizeof(extxmlinfo_t)) ;

#define	HEAD_PTR(P)	((extxmlhead_t *) P)
#define	INFO_PTR(P)	((extxmlinfo_t *) P)

#define	NODE2HEAD(P)	&((byte *) P)[-HEADSIZE]
#define	NODE2INFO(P)	&((byte *) P)[-HEADSIZE-INFOSIZE]

/* memory allocation
	node-information (size: INFOSIZE)
	node-type        (size: HEADSIZE)
	node-body	 (size: parameter)
 */

void * extXmlMalloc(size_t size)
{
	byte *		ptr ;
	byte *		bodyptr = NULL ;
	id <PXMLNode>	obj ;

	if(size == sizeof(xmlNode)){
		ptr = (byte *) [CMemAlloc allocate: size+HEADSIZE+INFOSIZE] ;
		if(ptr){
			bodyptr = ptr + HEADSIZE + INFOSIZE ;
			obj = [[CXMLNode alloc] initXMLNode: (xmlNodePtr) 
			  bodyptr] ;
			[CSystem checkPtr: obj] ;
			INFO_PTR(ptr)->xml_node = obj ;
			ptr += INFOSIZE ;
			HEAD_PTR(ptr)->ext_type = extxml_node ;
		}
	} else {
		ptr = (byte *) [CMemAlloc allocate: size + HEADSIZE] ;
		if(ptr){
			bodyptr = ptr + HEADSIZE ;
			HEAD_PTR(ptr)->ext_type = extxml_unknown ;
		}
	}
	return bodyptr ;
}

void * extXmlRealloc(void * ptr, size_t size)
{
	byte *		top ;
	byte *		result ;
	size_t		headsize ;

	if(ptr == NULL)
		return extXmlMalloc(size) ;
	top = NODE2HEAD(ptr) ;
	if(HEAD_PTR(top)->ext_type == extxml_node){
		top = NODE2INFO(ptr) ;
		headsize = HEADSIZE + INFOSIZE ;
		top = [CMemAlloc reallocate: top size: size + headsize] ;
		result = &top[headsize] ;
		[((extxmlinfo_t *) top)->xml_node resetNodePtr: result] ;
	} else {
		headsize = HEADSIZE ;
		top = [CMemAlloc reallocate: top size: size + headsize] ;
		result = &top[headsize] ;
	}
	return result ;
}

char * extXmlStrdup(const char * str)
{
	byte *	top ;
	size_t	len ;

	if(str == NULL)
		return NULL ;
	len = strlen(str) ;
	top = [CMemAlloc allocate: len+HEADSIZE+1] ;
	if(top){
		HEAD_PTR(top)->ext_type = extxml_unknown ;
		top += HEADSIZE ; 
		memmove(top, str, len+1) ;
	}
	return top ;
}

void extXmlFree(void * ptr)
{
	byte *		top ;
	extxmlinfo_t *	info ;

	if(ptr == NULL)
		return ;
	top = NODE2HEAD(ptr) ;
	if(HEAD_PTR(top)->ext_type == extxml_node){
		info = INFO_PTR(NODE2INFO(ptr)) ;
		[info->xml_node release] ;
		top = (byte *) info ;
	}
	[CMemAlloc free: top] ;
}

id <PXMLNode> xmlNodePtr2Object(xmlNodePtr node)
{
	byte * 		p = (byte *) node ;
	extxmlhead_t *	head = (extxmlhead_t *) NODE2HEAD(p) ;
	extxmlinfo_t *	info ;
	if(head->ext_type == extxml_node){
		info = INFO_PTR(NODE2INFO(p)) ;
		return info->xml_node ;
	} else
		return NULL ;
}

id <PXMLNode> newXMLNodeObject(xmlNsPtr ns, const xmlChar * name)
{
	xmlNodePtr	node ;

	node = xmlNewNode(ns, name) ;
	[CSystem checkPtr: node] ;
	return xmlNodePtr2Object(node) ;
}

id <PXMLNode> newXMLTextObject(const xmlChar *content)
{
	xmlNodePtr	node ;
	node = xmlNewText(content) ;
	[CSystem checkPtr: node] ;
	return xmlNodePtr2Object(node) ;
}

void destroyXMLNodeObject(id <PXMLNode> obj)
{
	xmlNodePtr	node = [obj getNodePtr] ;
	xmlUnlinkNode(node) ;
	xmlFreeNode(node) ; /* the destructor of obj is called here */
}

