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;
}
