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

/*
 * guppi-gnumeric-manger.c:
 *
 * Copyright (C) 2000-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-manager.h"
#include "guppi-gnumeric-version.h"
#include "guppi-gnumeric-vector.h"
#include "guppi-gnumeric-view.h"
#include "guppi-gnumeric-bonobo-view.h"
#include "guppi-gnumeric-type-selector.h"
#include "guppi-gnumeric-data-guru.h"
#include "guppi-gnumeric-format-guru.h"

#include <guppi-root-group-item.h>
#include <guppi-seq-scalar.h>
#include <guppi-seq-date.h>
#include <guppi-seq-string.h>
#include <guppi-useful.h>
#include <guppi-marker.h>

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

typedef struct {
	BonoboEmbeddableClass parent;

	POA_GUPPI_GNUMERIC_MANAGER(epv)	epv;
} GupGnmManagerClass;

#define GUP_GNM_MANAGER_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), GUP_GNM_MANAGER_TYPE, GupGnmManagerClass))
#define IS_GUP_GNM_MANAGER_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), GUP_GNM_MANAGER_TYPE))

/*************************************************************************/

static void
gup_gnm_manager_clear_arrangement (GupGnmManager *manager)
{
	if (manager->data_ids != NULL) {
		guppi_free (manager->data_ids);
		manager->data_ids = NULL;
		manager->header_ids = NULL;
		manager->arrangement_len = -1;
	}
}

static void
gup_gnm_manager_add_vector (GupGnmManager *manager, GupGnmVector *vector)
{
	int id;

	g_return_if_fail (IS_GUP_GNM_MANAGER (manager));
	g_return_if_fail (IS_GUP_GNM_VECTOR (vector));

	gup_gnm_manager_clear_arrangement (manager);

	id = gup_gnm_vector_id_get (vector);
	if (manager->vectors->len <= id)
		g_ptr_array_set_size (manager->vectors, id+1);
	g_ptr_array_index (manager->vectors, id) = vector;
}

GupGnmVector *
gup_gnm_manager_get_vector (GupGnmManager const *manager, unsigned id)
{
	g_return_val_if_fail (IS_GUP_GNM_MANAGER(manager), NULL);
	g_return_val_if_fail (manager->vectors != NULL, NULL);
	g_return_val_if_fail (manager->vectors->len > id, NULL);

	return g_ptr_array_index (manager->vectors, id);
}

static inline GupGnmManager *
gup_gnm_manager_from_servant (PortableServer_Servant servant)
{
	return GUP_GNM_MANAGER (bonobo_object_from_servant (servant));
}

static Bonobo_Control
impl_configure (PortableServer_Servant servant,
		const CORBA_char *type,
		CORBA_Environment *ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);
	GupGnmConfigGuru *cguru = NULL;

	ggd(0, printf ("Guppi : configure %s\n", type));

	gup_gnm_graph_set_spec (&manager->gurus, manager->graph.spec, TRUE);

	if (!strcmp (type, "DataGuru"))
		cguru = gup_gnm_data_guru_new (&manager->gurus);
	else if (!strcmp (type, "TypeSelector"))
		cguru = gup_gnm_type_selector_new (&manager->gurus);
	else if (!strcmp (type, "FormatGuru"))
		cguru = gup_gnm_format_guru_new (&manager->gurus);

	if (cguru == NULL)
		return CORBA_OBJECT_NIL;

	return CORBA_Object_duplicate (BONOBO_OBJREF (cguru), ev);
}

static GNOME_Gnumeric_Buffer *
impl_get_spec (PortableServer_Servant servant, CORBA_Environment *ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);
	GNOME_Gnumeric_Buffer *spec;
	xmlChar *mem;
	int size;

	xmlDocDumpMemory (manager->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_set_spec (PortableServer_Servant servant,
	       GNOME_Gnumeric_Buffer const *spec,
	       CORBA_Environment * ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);
	xmlParserCtxtPtr pctxt;

	ggd (1, puts ("Guppi : import spec"););

	/* A limit in libxml */
	g_return_if_fail (spec->_length >= 4);

	pctxt = xmlCreatePushParserCtxt (NULL, NULL,
		spec->_buffer, spec->_length, NULL);
	xmlParseChunk (pctxt, "", 0, TRUE);
	gup_gnm_graph_set_spec (&manager->graph, pctxt->myDoc, FALSE);
	xmlFreeParserCtxt (pctxt);
}

static GNOME_Gnumeric_Scalar_Vector
impl_addVector (PortableServer_Servant servant,
		const GNOME_Gnumeric_VectorSelection subscriber,
		const GNOME_Gnumeric_VectorType type,
		const GNOME_Gnumeric_VectorID id,
		const CORBA_char *default_fmt,
		CORBA_Environment *ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);
	GupGnmVector *vector;

	ggd(5, printf ("addVector manager == %p, type = %d, id = %d\n", manager, type, id));

	vector = gup_gnm_vector_new (subscriber, type, id);
	if (vector == NULL)
		return CORBA_OBJECT_NIL;
	gup_gnm_manager_add_vector (manager, vector);
	return gup_gnm_vector_servant_get (vector);
}

static void
impl_clearVectors (PortableServer_Servant servant,
		   CORBA_Environment * ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);

	ggd(5, printf ("clearVectors manager == %p\n", manager));
}

static void
impl_arrangeVectors (PortableServer_Servant servant,
		     GNOME_Gnumeric_VectorIDs const * data,
		     GNOME_Gnumeric_VectorIDs const * optional_headers,
		     CORBA_Environment * ev)
{
	GupGnmManager *manager = gup_gnm_manager_from_servant (servant);
	unsigned i;

	ggd(5, printf ("arrangeVectors manager == %p\n", manager));

	gup_gnm_manager_clear_arrangement (manager);

	manager->arrangement_len = data->_length;
	manager->data_ids = guppi_new (int, manager->arrangement_len *2);
	manager->header_ids = manager->data_ids + manager->arrangement_len;

	for (i = 0 ; i < manager->arrangement_len ; i++) {
		manager->data_ids[i] = data->_buffer[i];
		manager->header_ids[i] = optional_headers->_buffer[i];
	}

	gup_gnm_graph_generate_series (&manager->graph);
}

static GtkObjectClass *gup_gnm_manager_parent_class = NULL;

static void
gup_gnm_manager_destroy (GtkObject *obj)
{
	GupGnmManager *manager = GUP_GNM_MANAGER (obj);

	ggd(2, puts ("GUPPI : GupGnmManager destroyed"));

	gup_gnm_graph_release (&manager->graph);
	gup_gnm_graph_release (&manager->gurus);

	if (manager->vectors != NULL) {
		int i;
		
		i = manager->vectors->len;
		while (i-- > 0) {
			GupGnmVector *vector = g_ptr_array_index (manager->vectors, i);
			if (vector != NULL)
				guppi_unref (GTK_OBJECT (vector));
		}
		g_ptr_array_free (manager->vectors, TRUE);
		manager->vectors = NULL;
	}

	if (gup_gnm_manager_parent_class->destroy)
		gup_gnm_manager_parent_class->destroy (obj);
}

static void
gup_gnm_manager_class_init (GupGnmManagerClass *klass)
{
	GtkObjectClass *object_class = (GtkObjectClass *) klass;
	POA_GUPPI_GNUMERIC_MANAGER(epv) *epv = &klass->epv;

	object_class->destroy = gup_gnm_manager_destroy;

	gup_gnm_manager_parent_class = gtk_type_class (BONOBO_EMBEDDABLE_TYPE);

	epv->configure		= impl_configure;
	epv->_get_spec		= impl_get_spec;
	epv->_set_spec		= impl_set_spec;
	epv->addVector		= impl_addVector;
	epv->clearVectors	= impl_clearVectors;
	epv->arrangeVectors	= impl_arrangeVectors;
}

static void
gup_gnm_manager_init (GtkObject *object)
{
	GupGnmManager *manager = GUP_GNM_MANAGER (object);
	manager->vectors = g_ptr_array_new ();
	manager->data_ids = NULL;
	manager->header_ids = NULL;
	manager->arrangement_len = -1;

	gup_gnm_graph_construct (&manager->graph, manager);
	gup_gnm_graph_construct (&manager->gurus, manager);
}

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

	if (!type) {
		GtkTypeInfo info = {
			"GupGnmManager",
			sizeof (GupGnmManager),
			sizeof (GupGnmManagerClass),
			(GtkClassInitFunc) gup_gnm_manager_class_init,
			(GtkObjectInitFunc) gup_gnm_manager_init,
			NULL, /* reserved 1 */
			NULL, /* reserved 2 */
			(GtkClassInitFunc) NULL
		};

		type = bonobo_x_type_unique (
			BONOBO_EMBEDDABLE_TYPE,
			POA_GUPPI_GNUMERIC_MANAGER(init),
			POA_GUPPI_GNUMERIC_MANAGER(fini),
			GTK_STRUCT_OFFSET (GupGnmManagerClass, epv),
			&info);
	}

	return type;
}

static void
gup_gnm_manager_print (GnomePrintContext * ctx, double width, double height,
		       Bonobo_PrintScissor const *scissor, gpointer graph)
{
	GuppiRootGroupView *plot = gup_gnm_graph_get_view (graph);
	guppi_element_view_print_to_bbox (GUPPI_ELEMENT_VIEW (plot),
		ctx, 0, 0, width, height);
}

GupGnmManager *
gup_gnm_manager_new (void)
{
	GupGnmManager *manager;
	BonoboPrint *print;

	manager = guppi_type_new (GUP_GNM_MANAGER_TYPE);
	bonobo_embeddable_construct (BONOBO_EMBEDDABLE (manager),
		gup_gnm_bonobo_view_factory, NULL);

	ggd(2, printf ("Manager::new() == %p\n", manager));

	/* Register the Bonobo::Print interface */
	print = bonobo_print_new (gup_gnm_manager_print, &manager->graph);
	if (!print) {
		bonobo_object_unref (BONOBO_OBJECT (manager));
		return NULL;
	}

	bonobo_object_add_interface (BONOBO_OBJECT (manager),
		BONOBO_OBJECT (print));


	return manager;
}


syntax highlighted by Code2HTML, v. 0.9.1