static const char version[] = "$Id$";

/* 
* Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
*
* See the COPYING file for the terms of usage and distribution.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "malloc.h"
#include "error.h"
#include "domnode.h"

/* TODO: generic format support */
#include "domnode-xml.h"

/******************************************************************************/
extern sd_domnode_t* __sd_domnode_new(const char* a_name, const char* a_value,
									  int is_elem)
{
	sd_domnode_t* ptrThis;

	ptrThis = (sd_domnode_t*)sd_calloc(1, sizeof(*ptrThis));

	ptrThis->name     = a_name    ? sd_strdup(a_name) : 0;
	ptrThis->value    = a_value   ? sd_strdup(a_value): 0;
	ptrThis->children = is_elem ? sd_list_new(10) : 0;
	ptrThis->attrs    = is_elem ? sd_list_new(10) : 0;

	return ptrThis;
}

/******************************************************************************/
extern sd_domnode_t* sd_domnode_new(const char* a_name, const char* a_value)
{
	return __sd_domnode_new(a_name, a_value, 1);
}

/******************************************************************************/
static int foreach_delete(sd_domnode_t* a_node, void* unused)
{
	sd_domnode_delete(a_node);
	return 0;
}

/******************************************************************************/
static void domnode_clear(sd_domnode_t* ptrThis)
{
	free((void*) ptrThis->name);
	free((void*) ptrThis->value);

	sd_list_foreach(ptrThis->children, (sd_list_func_t) foreach_delete, 0);
	sd_list_delete(ptrThis->children);

	sd_list_foreach(ptrThis->attrs, (sd_list_func_t) foreach_delete, 0);
	sd_list_delete(ptrThis->attrs);
}

/******************************************************************************/
extern void sd_domnode_delete(sd_domnode_t* ptrThis)
{
	if (!ptrThis)
		return;

	domnode_clear(ptrThis);
	free(ptrThis);
}

/******************************************************************************/
static void domnode_update(sd_domnode_t* ptrThis, sd_domnode_t* a_node)
{
	domnode_clear(ptrThis);
	ptrThis->name	= a_node->name;
	ptrThis->value	= a_node->value;
	ptrThis->children = a_node->children;
	ptrThis->attrs	= a_node->attrs;

	/* Destroy ptrThis now empty node ! */
	free(a_node);
}

/******************************************************************************/
extern int sd_domnode_fread(sd_domnode_t* ptrThis, FILE* a_stream)
{
	int ret;
	sd_domnode_t* node;

	/* TODO: generic format support */
	if (! (ret = __sd_domnode_xml_fread(&node, a_stream)))
		domnode_update(ptrThis, node);

	return ret ? -1 : 0;
}

/******************************************************************************/
extern int sd_domnode_read(sd_domnode_t* ptrThis, const char* a_buffer,
						   size_t a_size)
{
	int ret;
	sd_domnode_t* node;

	/* TODO: generic format support */
	if (! (ret = __sd_domnode_xml_read(&node, a_buffer, a_size)))
		domnode_update(ptrThis, node);

	return ret ? -1 : 0;
}

/******************************************************************************/
extern int sd_domnode_write(sd_domnode_t* ptrThis, char** a_buffer,
							size_t* a_size)
{
	/* TODO: generic format support */
	return __sd_domnode_xml_write(ptrThis, a_buffer, a_size);
}

/******************************************************************************/
extern int sd_domnode_fwrite(const sd_domnode_t* ptrThis, FILE* a_stream)
{
	/* TODO: generic format support */
	return __sd_domnode_xml_fwrite(ptrThis, a_stream);
}

/******************************************************************************/
extern int sd_domnode_load(sd_domnode_t* ptrThis, const char* a_filename)
{
	FILE* fp;
	int   ret = 0;

	if ( (fp = fopen(a_filename, "r")) == 0)
		return -1;

	ret = sd_domnode_fread(ptrThis, fp);

	fclose(fp);
	return ret;
}

/******************************************************************************/
extern int sd_domnode_store(const sd_domnode_t* ptrThis, const char* afilename)
{
	FILE* fp;
	int   ret = 0;

	if ( (fp = fopen(afilename, "w")) == 0)
		return -1;

	ret = sd_domnode_fwrite(ptrThis, fp);

	fclose(fp);
	return ret;
}

/******************************************************************************/
extern sd_domnode_t* sd_domnode_search(const sd_domnode_t* ptrThis,
									   const char* a_name)
{
	sd_list_iter_t* i;

	for (i = sd_list_begin(ptrThis->children); i != sd_list_end(ptrThis->children); 
		i = sd_list_iter_next(i)) {
			sd_domnode_t* node = (sd_domnode_t*)i->data;

			if (strcmp(node->name, a_name) == 0)
				return node;
	}

	for (i = sd_list_begin(ptrThis->attrs); i != sd_list_end(ptrThis->attrs); 
		i = sd_list_iter_next(i)) {
			sd_domnode_t* node = (sd_domnode_t*)i->data;

			if (strcmp(node->name, a_name) == 0)
				return node;
	}

	for (i = sd_list_begin(ptrThis->children); i != sd_list_end(ptrThis->children); 
		i = sd_list_iter_next(i)) {
			sd_domnode_t* node = (sd_domnode_t*)i->data;

			if ((node = sd_domnode_search(node, a_name)) != 0)
				return node;
	}

	return 0;
}

/******************************************************************************/
extern sd_domnode_t* sd_domnode_attrs_put(sd_domnode_t* ptrThis,
										  sd_domnode_t* a_attr)
{
	sd_list_iter_t* i;

	if (!ptrThis || !ptrThis->attrs || !a_attr || !a_attr->value)
		return 0;

	if ((i = sd_list_lookadd(ptrThis->attrs, a_attr)) == sd_list_end(ptrThis->attrs))
		return 0;

	return (sd_domnode_t*)i->data;
}

/******************************************************************************/
extern sd_domnode_t* 
sd_domnode_attrs_get(const sd_domnode_t* ptrThis, const char* a_name)
{
	sd_list_iter_t* i;

	if (!ptrThis || !ptrThis->attrs || !a_name || !*a_name)
		return 0;

	for (i = sd_list_begin(ptrThis->attrs); i != sd_list_end(ptrThis->attrs); 
		i = sd_list_iter_next(i)) {
			sd_domnode_t* node = (sd_domnode_t*)i->data;

			if (strcmp(node->name, a_name) == 0)
				return node;
	}

	return 0;
}

/******************************************************************************/
extern sd_domnode_t* 
sd_domnode_attrs_remove(sd_domnode_t* ptrThis, const char* a_name)
{
	sd_list_iter_t* i;

	if (!ptrThis || !ptrThis->attrs || !a_name || !*a_name)
		return 0;

	for (i = sd_list_begin(ptrThis->attrs); i != sd_list_end(ptrThis->attrs);
		i = sd_list_iter_next(i)) {
			sd_domnode_t* node = (sd_domnode_t*)i->data;

			if (strcmp(node->name, a_name) == 0) {
				sd_list_iter_del(i);
				return node;
			}
	}

	return 0;
}
