/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* vim: set sw=8: */

/*
 * guppi-gnumeric-xml.c: utilites for manipulating the xml spec
 * 			used to describe a graph.
 *
 * Copyright (C) 2001 Ximian, Inc
 *
 * Developed by Jody Goldberg (jgoldberg@home.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include "guppi-gnumeric-xml.h"
#include "guppi-gnumeric-graph.h"
#include "guppi-gnumeric-manager.h"
#include "guppi-gnumeric-vector.h"

#include <guppi-string.h>
#include <guppi-rgb.h>

#include <gal/util/e-xml-utils.h>
#include <gnome-xml/xmlmemory.h>
#include <errno.h>

xmlNode	*
gup_gnm_graph_get_plot (GupGnmGraph *graph, int plotID)
{
	xmlNode *plot;

	g_return_val_if_fail (graph != NULL, NULL);

	if (graph->spec == NULL)
		return NULL;

	plot = e_xml_get_child_by_name (graph->spec->xmlRootNode, "Plots");
	g_return_val_if_fail (plot != NULL, NULL);

	for (plot = plot->xmlChildrenNode ; plot ; plot = plot->next)
		if (!strcmp (plot->name, "Plot") &&
		    gup_gnm_plot_get_id (plot) == plotID)
			return plot;
	return NULL;
}

gboolean
gup_gnm_graph_foreach_series (GupGnmGraph *graph, GupGnmSeriesFn func, gpointer user)
{
	xmlNode *plot, *series;

	if (graph->spec == NULL)
		return FALSE;

	plot = e_xml_get_child_by_name (graph->spec->xmlRootNode, "Plots");

	g_return_val_if_fail (plot != NULL, TRUE);

	for (plot = plot->xmlChildrenNode ; plot ; plot = plot->next) {
		if (strcmp (plot->name, "Plot"))
			continue;
		series = e_xml_get_child_by_name (plot, "Data");
		if (series == NULL)
			continue;
		for (series = series->xmlChildrenNode ; series ; series = series->next) {
			if (strcmp (series->name, "Series"))
				continue;
			if ((*func)(graph, plot, series, user))
				return TRUE;
		}
	}
	return FALSE;
}

int
gup_gnm_plot_get_id (xmlNode *plot)
{
	/* FIXME : get an 'ID' rather than using index */
	return e_xml_get_integer_prop_by_name_with_default (plot, "index", -1);
}

int
gup_gnm_series_get_id (xmlNode *series)
{
	/* FIXME : get an 'ID' rather than using index */
	return e_xml_get_integer_prop_by_name_with_default (series, "index", -1);
}

static inline int
gup_gnm_dimension_get_vectorID (xmlNode *dim)
{
	return e_xml_get_integer_prop_by_name_with_default (dim, "ID", -1);
}

xmlNode *
gup_gnm_series_get_dimension (xmlNode *series, char const *target_dim_name)
{
	xmlNode *dim;
	xmlChar *dim_name;
	
	for (dim = series->xmlChildrenNode; dim != NULL ; dim = dim->next) {
		if (strcmp (dim->name, "Dimension"))
			continue;
		dim_name = xmlGetProp (dim, "dim_name");

		if (dim_name != NULL) {
			gboolean const res = (strcmp (dim_name, target_dim_name) == 0);
			xmlFree (dim_name);
			if (res)
				return dim;
		}
	}
	return NULL;
}


GupGnmVector *
gup_gnm_series_dim_get_vector (xmlNode *series, char const *dim_name,
			   GupGnmGraph const *graph)
{
	xmlNode *dim = gup_gnm_series_get_dimension (series, dim_name);

	if (dim != NULL) {
		int id = gup_gnm_dimension_get_vectorID (dim);
		if (id >= 0)
			return gup_gnm_manager_get_vector (graph->manager, id);
	}
	return NULL;
}

GuppiSeqScalar *
gup_gnm_series_dim_get_scalar (xmlNode *series, char const *dim,
			       GupGnmGraph const *graph)
{
	GupGnmVector *vec = gup_gnm_series_dim_get_vector (series, dim, graph);
	if (vec != NULL)
		return gup_gnm_vector_get_scalar (vec);
	return NULL;
}

GuppiSeqString *
gup_gnm_series_dim_get_string (xmlNode *series, char const *dim,
			       GupGnmGraph const *graph)
{
	GupGnmVector *vec = gup_gnm_series_dim_get_vector (series, dim, graph);
	if (vec != NULL)
		return gup_gnm_vector_get_string (vec);
	return NULL;
}

void
gup_gnm_series_add_dimension (xmlNode *series, char const *dim_name, int id)
{
	xmlNode *vec = xmlNewChild (series, series->ns, "Dimension", NULL);
	xmlSetProp (vec, "dim_name", dim_name);
	e_xml_set_integer_prop_by_name (vec, "ID", id);
}

xmlNode *
gup_gnm_attr_get (xmlNode *node, char const *name)
{
	return node ? e_xml_get_child_by_name (node, name) : NULL;
}

gboolean
gup_gnm_attr_get_bool (xmlNode *node, char const *name, gboolean default_val)
{
	xmlChar *content;
	gboolean res;

	node = gup_gnm_attr_get (node, name);
	if (node == NULL)
		return default_val;

	content = xmlNodeGetContent (node);
	if (content == NULL)
		return TRUE;  /* <foo/> == <foo>true</foo> */

	res = guppi_string2boolean (content);
	xmlFree (content);

	return res;
}

int
gup_gnm_attr_get_int (xmlNode *node, char const *name, int default_val)
{
	xmlChar *content;
	char *end;
	int res;

	node = gup_gnm_attr_get (node, name);
	if (node == NULL)
		return default_val;

	content = xmlNodeGetContent (node);
	g_return_val_if_fail (content != NULL, default_val);

	errno = 0; /* strto(ld) sets errno, but does not clear it.  */
	res = strtol (content, &end, 10);
	xmlFree (content);

	g_return_val_if_fail (errno != ERANGE, default_val);
	g_return_val_if_fail ((char *)content != end, default_val);

	return res;
}

double
gup_gnm_attr_get_double (xmlNode *node, char const *name, double default_val)
{
	xmlChar *content;
	char *end;
	double res;

	node = gup_gnm_attr_get (node, name);
	if (node == NULL)
		return default_val;

	content = xmlNodeGetContent (node);
	g_return_val_if_fail (content != NULL, default_val);

	errno = 0; /* strto(ld) sets errno, but does not clear it.  */
	res = strtod (content, &end);
	xmlFree (content);

	g_return_val_if_fail (errno != ERANGE, default_val);
	g_return_val_if_fail ((char *)content != end, default_val);

	return res;
}

guint32
gup_gnm_attr_get_color (xmlNode *node, char const *name, guint32 default_val)
{
	xmlChar *content;
	guint32 res = default_val;
	int r, g, b;

	node = gup_gnm_attr_get (node, name);
	if (node == NULL)
		return default_val;

	content = xmlNodeGetContent (node);
	g_return_val_if_fail (content != NULL, default_val);

	if (sscanf (content, "%X:%X:%X", &r, &g, &b) == 3)
		res = RGB_TO_RGBA(RGB_TO_UINT(r,g,b) ,0xff);
	xmlFree (content);

	return res;
}

GuppiMarker
gup_gnm_attr_get_marker (xmlNode *node, char const *name,
			 GuppiMarker default_val)
{
	xmlChar *content;
	guint32 res;

	node = gup_gnm_attr_get (node, name);
	if (node == NULL)
		return default_val;

	content = xmlNodeGetContent (node);
	g_return_val_if_fail (content != NULL, default_val);

	res = guppi_str2marker (content);
	xmlFree (content);

	g_return_val_if_fail (res != GUPPI_MARKER_UNKNOWN, default_val);

	return res;
}


syntax highlighted by Code2HTML, v. 0.9.1