/*
 * xml - A plugin for xml objects for the opensync framework
 * Copyright (C) 2004-2005  Armin Bauer <armin.bauer@opensync.org>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 * 
 */
 
#include "opensync.h"
#include "opensync_internals.h"

xmlNode *osxml_node_add_root(xmlDoc *doc, const char *name)
{
	doc->children = xmlNewDocNode(doc, NULL, (xmlChar*)name, NULL);
	return doc->children;
}

xmlNode *osxml_node_get_root(xmlDoc *doc, const char *name, OSyncError **error)
{
	xmlNode *cur = xmlDocGetRootElement(doc);
	if (!cur) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get xml root element");
		return NULL;
	}
	
	if (xmlStrcmp((cur)->name, (const xmlChar *) name)) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Wrong xml root element");
		return NULL;
	}
	
	cur = (cur)->xmlChildrenNode;
	return cur;
}

void osxml_node_set(xmlNode *node, const char *name, const char *data, OSyncXMLEncoding encoding)
{
	if (name)
		xmlNodeSetName(node, (xmlChar*)name); //FIXME Free previous name?
		
	if (data)
		xmlNewTextChild(node, NULL, (xmlChar*)"Content", (xmlChar*)data);
}

xmlNode *osxml_node_add(xmlNode *parent, const char *name, const char *data)
{
	if (!data)
		return NULL;
	if (strlen(data) == 0)
		return NULL;
	xmlNode *node = xmlNewTextChild(parent, NULL, (xmlChar*)name, (xmlChar*)data);
	return node;
}

void osxml_node_add_property(xmlNode *parent, const char *name, const char *data)
{
	xmlNewProp(parent, (xmlChar*)name, (xmlChar*)data);
}

void osxml_node_mark_unknown(xmlNode *parent)
{
	if (!xmlHasProp(parent, (xmlChar*)"Type"))
		xmlNewProp(parent, (xmlChar*)"Type", (xmlChar*)"Unknown");
}

void osxml_node_remove_unknown_mark(xmlNode *node)
{
	xmlAttr *attr = xmlHasProp(node, (xmlChar*)"Type");
	if (!attr)
		return;
	xmlRemoveProp(attr);
}

xmlNode *osxml_get_node(xmlNode *parent, const char *name)
{
	xmlNode *cur = (parent)->xmlChildrenNode;
	while (cur) {
		if (!xmlStrcmp(cur->name, (const xmlChar *)name))
			return cur;
		cur = cur->next;
	}
	return NULL;
}

char *osxml_find_node(xmlNode *parent, const char *name)
{
	return (char*)xmlNodeGetContent(osxml_get_node(parent, name));
}

xmlXPathObject *osxml_get_nodeset(xmlDoc *doc, const char *expression)
{
	xmlXPathContext *xpathCtx = NULL;
	xmlXPathObject *xpathObj = NULL;
    
    /* Create xpath evaluation context */
    xpathCtx = xmlXPathNewContext(doc);
    if(xpathCtx == NULL) {
        fprintf(stderr,"Error: unable to create new XPath context\n");
        return NULL;
    }
    
    /* Evaluate xpath expression */
    xpathObj = xmlXPathEvalExpression((xmlChar*)expression, xpathCtx);
    if(xpathObj == NULL) {
        fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
        xmlXPathFreeContext(xpathCtx); 
        return NULL;
    }

	xmlXPathFreeContext(xpathCtx);
	/* Cleanup of XPath data */
   // xmlXPathFreeObject(xpathObj);
   return xpathObj;
}

xmlXPathObject *osxml_get_unknown_nodes(xmlDoc *doc)
{
	return osxml_get_nodeset(doc, "/*/*[@Type='Unknown']");
}

void osxml_map_unknown_param(xmlNode *node, const char *paramname, const char *newname)
{
	xmlNode *cur = node->xmlChildrenNode;
	while (cur) {
		if (xmlStrcmp(cur->name, (const xmlChar *)"UnknownParam"))
			goto next;
		
		char *name = osxml_find_node(cur, "ParamName");
		char *content = osxml_find_node(cur, "Content");
		if (!strcmp(name, paramname)) {
			osxml_node_add(node, newname, content);
			osxml_node_remove_unknown_mark(node);
			
			xmlUnlinkNode(cur);
			xmlFreeNode(cur);
			g_free(name);
			g_free(content);
			return;
		}
		
		g_free(name);
		g_free(content);
			
		next:;
		cur = cur->next;
	}
}

osync_bool osxml_has_property_full(xmlNode *parent, const char *name, const char *data)
{
	if (osxml_has_property(parent, name))
		return (strcmp((char*)xmlGetProp(parent, (xmlChar*)name), data) == 0);
	return FALSE;
}

char *osxml_find_property(xmlNode *parent, const char *name)
{
	return (char*)xmlGetProp(parent, (xmlChar*)name);
}

osync_bool osxml_has_property(xmlNode *parent, const char *name)
{
	return (xmlHasProp(parent, (xmlChar*)name) != NULL);
}

xmlChar *osxml_write_to_string(xmlDoc *doc)
{
	xmlKeepBlanksDefault(0);
	xmlChar *temp = NULL;
	int size = 0;
	xmlDocDumpFormatMemoryEnc(doc, &temp, &size, NULL, 1);
	return temp;
}

osync_bool osxml_copy(const char *input, int inpsize, char **output, int *outpsize)
{
	xmlDoc *doc = (xmlDoc *)(input);
	xmlDoc *newdoc = xmlCopyDoc(doc, TRUE);
	*output = (char *)newdoc;
	*outpsize = sizeof(newdoc);
	return TRUE;
}

osync_bool osxml_marshall(const char *input, int inpsize, char **output, int *outpsize, OSyncError **error)
{
	xmlDoc *doc = (xmlDoc*)input;
	xmlChar *result;
	int size;
	xmlDocDumpMemory(doc, &result, &size);
	*output = (char*)result;
	*outpsize = size;
	return TRUE;
}

osync_bool osxml_demarshall(const char *input, int inpsize, char **output, int *outpsize, OSyncError **error)
{
	xmlDoc *doc = xmlParseMemory(input, inpsize);
	if (!doc) {
		osync_error_set(error, OSYNC_ERROR_GENERIC, "Invalid XML data received");
		goto error;
	}

	*output = (char*)doc;
	*outpsize = sizeof(*doc);
	return TRUE;

error:
	return FALSE;
}




syntax highlighted by Code2HTML, v. 0.9.1