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

/*
 * guppi-gnumeric-config-guru.c: Manage
 *
 * Copyright (C) 2001 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-data-guru.h"
#include "guppi-gnumeric-config-guru.h"
#include "guppi-gnumeric-manager.h"
#include "guppi-gnumeric-view.h"
#include "guppi-gnumeric-xml.h"

#include <guppi-memory.h>
#include <gal/util/e-xml-utils.h>

struct _GupGnmDataGuru {
	GupGnmConfigGuru parent;

	GupGnmView view;
};

typedef struct {
	GupGnmConfigGuruClass parent_class;

	POA_GUPPI_GNUMERIC_DATA_GURU(epv) epv;
} GupGnmDataGuruClass;

#define GUP_GNM_DATA_GURU_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), GUP_GNM_DATA_GURU_TYPE, GupGnmDataGuruClass))
#define IS_GUP_GNM_DATA_GURU_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), GUP_GNM_DATA_GURU_TYPE))

static BonoboControlClass *gup_gnm_data_guru_parent_class = NULL;

static GNOME_Gnumeric_Buffer *
impl_get_spec (PortableServer_Servant servant, CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);
	GNOME_Gnumeric_Buffer *spec;
	xmlChar *mem = NULL;
	int size = 0;

	if (graph != NULL)
		xmlDocDumpMemory (graph->spec, &mem, &size);

	spec = GNOME_Gnumeric_Buffer__alloc ();
	spec->_length = spec->_maximum = size;
	spec->_buffer = CORBA_sequence_CORBA_octet_allocbuf(size);
	spec->_release = CORBA_TRUE;

	memcpy (spec->_buffer, mem, size);
	xmlFree (mem);

	return spec;
}

static void
impl_seriesSetDimension (PortableServer_Servant servant,
			 const GNOME_Gnumeric_SeriesID seriesID,
			 const CORBA_char *dim,
			 const GNOME_Gnumeric_VectorID vectorID,
			 CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);

	g_return_if_fail (graph != NULL);

	ggd(5, printf ("seriesSetDimension guru == %p\n", cguru));
	if (gup_gnm_graph_set_series_dim (graph, seriesID, dim, vectorID))
		gup_gnm_graph_regenerate_plots (graph);
}

static GNOME_Gnumeric_PlotID
impl_plotAdd (PortableServer_Servant servant,
	      CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);

	g_return_val_if_fail (graph != NULL, -1);

	ggd(5, printf ("plotAdd data-guru == %p\n", cguru));
	return -1;
}

static void
impl_plotDelete (PortableServer_Servant servant,
		 const GNOME_Gnumeric_PlotID plot,
		 CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);

	g_return_if_fail (graph != NULL);

	ggd(5, printf ("plotDelete data-guru == %p\n", cguru));
}

typedef struct {
	GNOME_Gnumeric_SeriesID max;
	xmlNode *sibling;
} SeriesAddClosure;
static gboolean
cb_find_max_index (GupGnmGraph *graph,
		   xmlNode *plot, xmlNode *series,
		   gpointer user)
{
	SeriesAddClosure *closure = user;
	int ID = gup_gnm_series_get_id (series);

	if (closure->max < ID)
		closure->max = ID;

	if (closure->sibling == NULL)
		closure->sibling = series;
	return FALSE;
}

static GNOME_Gnumeric_SeriesID
impl_seriesAdd (PortableServer_Servant servant,
		const GNOME_Gnumeric_PlotID plotID,
		CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);
	xmlNode		 *data, *plot, *series;
	SeriesAddClosure  user;

	g_return_val_if_fail (graph != NULL, -1);

	ggd(5, printf ("seriesAdd data-guru == %p\n", cguru));

	plot = gup_gnm_graph_get_plot (graph, plotID);
	if (plot == NULL)
		return -1;
	data = e_xml_get_child_by_name (plot, "Data");
	if (data == NULL)
		return -1;

	user.max = -1;
	user.sibling = NULL;
	gup_gnm_graph_foreach_series (graph, cb_find_max_index, &user);
	user.max++;
	series = xmlNewChild (data, data->ns, "Series", NULL);
	e_xml_set_integer_prop_by_name (series, "index", user.max);

	/* series is blank, no need to regenerate, but we should add markup */
	if (user.sibling != NULL) {
		GupGnmPlotDescriptor const *descriptor = gup_gnm_plot_get_descriptor (plot);

		if (descriptor != NULL) {
			int i = 0;
			for (i = 0; descriptor->spec [i].display_name != NULL ; i++)
				if (descriptor->spec [i].shared) {
					xmlNode *sibling = gup_gnm_series_get_dimension  (user.sibling,
						descriptor->spec [i].dim_name);
					if (sibling != NULL)
						xmlAddChild (series, xmlCopyNode (sibling, TRUE));
				}
		} else {
			g_warning ("Unkown plot type");
		}
	}

	gup_gnm_graph_markup_spec (graph);

	return user.max;
}

static gboolean
cb_series_delete (GupGnmGraph *graph,
		  xmlNode *plot, xmlNode *series,
		  gpointer user)
{
	int targetID = GPOINTER_TO_INT (user);
	int ID = gup_gnm_series_get_id (series);

	if (targetID == ID) {
		xmlUnlinkNode (series);
		xmlFreeNode (series);
		gup_gnm_graph_markup_spec (graph);
		gup_gnm_graph_regenerate_plots (graph);
		return TRUE;
	}
	return FALSE;
}

static void
impl_seriesDelete (PortableServer_Servant servant,
		   const GNOME_Gnumeric_SeriesID seriesID,
		   CORBA_Environment *ev)
{
	GupGnmConfigGuru *cguru = gup_gnm_config_guru_from_servant (servant);
	GupGnmGraph	 *graph = gup_gnm_config_guru_get_graph	(cguru);

	g_return_if_fail (graph != NULL);

	ggd(5, printf ("seriesDelete data-guru == %p\n", cguru));
	gup_gnm_graph_foreach_series (graph, cb_series_delete,
		GINT_TO_POINTER (seriesID));
}

static void
gup_gnm_data_guru_destroy (GtkObject *obj)
{
	GupGnmDataGuru *dguru = GUP_GNM_DATA_GURU (obj);

	ggd (1, printf ("Destroy data guru %p \n", dguru););

	GTK_OBJECT_CLASS (gup_gnm_data_guru_parent_class)->destroy (obj);
}

static void
gup_gnm_data_guru_class_init (GupGnmDataGuruClass *klass)
{
	GtkObjectClass *object_class = (GtkObjectClass *) klass;
	POA_GUPPI_GNUMERIC_DATA_GURU(epv) *epv = &klass->epv;

	gup_gnm_data_guru_parent_class = gtk_type_class (gup_gnm_config_guru_get_type ());
	object_class->destroy   = gup_gnm_data_guru_destroy;

	epv->seriesSetDimension	= impl_seriesSetDimension;
	epv->_get_spec		= impl_get_spec;
	epv->plotAdd		= impl_plotAdd;
	epv->plotDelete		= impl_plotDelete;
	epv->seriesAdd		= impl_seriesAdd;
	epv->seriesDelete	= impl_seriesDelete;
}

GtkType
gup_gnm_data_guru_get_type (void)
{
	static GtkType type = 0;

	if (!type) {
		GtkTypeInfo info = {
			"GupGnmDataGuru",
			sizeof (GupGnmDataGuru),
			sizeof (GupGnmDataGuruClass),
			(GtkClassInitFunc) gup_gnm_data_guru_class_init,
			(GtkObjectInitFunc) NULL,
			NULL,			/* reserved 1 */
			NULL,			/* reserved 2 */
			(GtkClassInitFunc) NULL
		};

		type = bonobo_x_type_unique (
			GUP_GNM_CONFIG_GURU_TYPE,
			POA_GUPPI_GNUMERIC_DATA_GURU(init),
			POA_GUPPI_GNUMERIC_DATA_GURU(fini),
			GTK_STRUCT_OFFSET (GupGnmDataGuruClass, epv),
			&info);
	}

	return type;
}

GupGnmConfigGuru *
gup_gnm_data_guru_new (GupGnmGraph *graph)
{
	GupGnmDataGuru *dguru = guppi_type_new (GUP_GNM_DATA_GURU_TYPE);

	ggd(5, printf ("gup_gnm_data_guru_new == %p\n", dguru));

	gup_gnm_view_construct (&dguru->view, graph);
	return gup_gnm_config_guru_construct (GUP_GNM_CONFIG_GURU (dguru),
		graph, GTK_WIDGET (dguru->view.canvas));
}


syntax highlighted by Code2HTML, v. 0.9.1