/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * god-drawing-ms-client-handler-ppt.c: MS Office Graphic Object support
 *
 * Copyright (C) 2000-2004
 *	Jody Goldberg (jody@gnome.org)
 *	Michael Meeks (mmeeks@gnu.org)
 *      Christopher James Lahey <clahey@ximian.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 <libpresent/god-drawing-ms-client-handler-ppt.h>
#include "ppt-types.h"
#include <goffice/utils/go-units.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-input.h>
#include <gsf/gsf-utils.h>
#include <string.h>
#include <goffice/ms-compat/go-ms-parser.h>
#include "ppt-parsing-helper.h"

#define CVS_VERSION "$Id: god-drawing-ms-client-handler-ppt.c,v 1.8 2005/08/01 20:37:05 clahey Exp $"
#define ERROR_STRING(cond,str) G_STRLOC "\n<" CVS_VERSION ">\n" str " (" #cond ")"
#define ERROR(cond,str) { \
	if (!(cond)) { \
		if (err) \
			g_set_error (err, domain, code, ERROR_STRING(cond,str)); \
		else \
			g_warning (ERROR_STRING(cond,str)); \
		return; \
	} \
}
#define ERROR_RETVAL(cond,str,retval) { \
	if (!(cond)) { \
		if (err) \
			g_set_error (err, domain, code, ERROR_STRING(cond,str)); \
		else \
			g_warning (ERROR_STRING(cond,str)); \
		return retval; \
	} \
}

static GQuark domain;
static gint code;

static GObjectClass *parent_class;

struct GodDrawingMsClientHandlerPptPrivate_ {
	PresentSlide *slide;
	GPtrArray *fonts;
};

static const GOMSParserRecordType types[] =
{
	{	TextCharsAtom,			"TextCharsAtom",		FALSE,	TRUE,	-1,	-1	},
	{	TextBytesAtom,			"TextBytesAtom",		FALSE,	TRUE,	-1,	-1	},
	{	OutlineTextRefAtom,		"OutlineTextRefAtom",		FALSE,	TRUE,	-1,	-1	},
	{	StyleTextPropAtom,		"StyleTextPropAtom",		FALSE,	TRUE,	-1,	-1	},
};

GodDrawingMsClientHandler *
god_drawing_ms_client_handler_ppt_new (PresentSlide *slide, GPtrArray *fonts)
{
	GodDrawingMsClientHandler *handler;

	handler = g_object_new (GOD_DRAWING_MS_CLIENT_HANDLER_PPT_TYPE, NULL);

	GOD_DRAWING_MS_CLIENT_HANDLER_PPT(handler)->priv->slide = slide;
	GOD_DRAWING_MS_CLIENT_HANDLER_PPT(handler)->priv->fonts = fonts;

	return handler;
}

static void
god_drawing_ms_client_handler_ppt_init (GObject *object)
{
	GodDrawingMsClientHandlerPpt *handler = GOD_DRAWING_MS_CLIENT_HANDLER_PPT (object);
	handler->priv = g_new0 (GodDrawingMsClientHandlerPptPrivate, 1);
}

static void
god_drawing_ms_client_handler_ppt_finalize (GObject *object)
{
	GodDrawingMsClientHandlerPpt *handler = GOD_DRAWING_MS_CLIENT_HANDLER_PPT (object);

	g_free (handler->priv);
	handler->priv = NULL;

	G_OBJECT_CLASS (parent_class)->finalize (object);
}

typedef struct {
	GodTextModel *text_model;
	GodDrawingMsClientHandlerPpt *handler;
} TextParseState;

static void
handle_atom (GOMSParserRecord *record, GSList *stack, const guint8 *data, GsfInput *input, GError **err, gpointer user_data)
{
	TextParseState *parse_state = user_data;
	switch (record->opcode) {
	case TextCharsAtom:
		{
			char *text;
			ERROR (stack == NULL, "TextCharsAtom is root only inside ClientTextbox.");
			ERROR (parse_state->text_model == NULL, "Only one text per ClientTextbox.");
			
			text = g_utf16_to_utf8 ((gunichar2 *) data, record->length / 2, NULL, NULL, NULL);
			parse_state->text_model = god_text_model_new ();
			god_text_model_set_text (parse_state->text_model, text);
			g_free (text);
		}
		break;
	case TextBytesAtom:
		{
			char *text;
			ERROR (stack == NULL, "TextBytesAtom is root only inside ClientTextbox.");
			ERROR (parse_state->text_model == NULL, "Only one text per ClientTextbox.");

			text = g_convert (data, record->length, "utf8", "latin1", NULL, NULL, NULL);
			parse_state->text_model = god_text_model_new ();
			god_text_model_set_text (parse_state->text_model, text);
			g_free (text);
		}
		break;
	case OutlineTextRefAtom:
		{
			int outline_text_ref;
			PresentSlide *slide;
			int i, text_count;

			ERROR (stack == NULL, "OutlineTextRefAtom is root only inside ClientTextbox.");
			ERROR (parse_state->text_model == NULL, "Only one text per ClientTextbox.");

			slide = parse_state->handler->priv->slide;

			outline_text_ref = GSF_LE_GET_GUINT32 (data);

			if (slide) {
				text_count = present_slide_get_text_count (slide);
				for (i = 0; i < text_count; i++) {
					PresentText *text = present_slide_get_text (slide, i);
					if (present_text_get_text_id (text) == outline_text_ref) {
						parse_state->text_model = GOD_TEXT_MODEL (text);
						break;
					}
					g_object_unref (text);
				}
			}
		}
		break;
	case StyleTextPropAtom:
		{
			ERROR (stack == NULL, "StyleTextPropAtom is root only inside ClientTextbox.");
			ERROR (parse_state->text_model != NULL, "Must have text before StyleTextPropAtom inside ClientTextbox.");

			ppt_parsing_helper_parse_style_text_prop_atom (data, record->length, parse_state->text_model, parse_state->handler->priv->fonts);
		}
		break;
	}
}

static GOMSParserCallbacks callbacks = { handle_atom,
					 NULL,
					 NULL };

static GodTextModel *
god_drawing_ms_client_handler_ppt_handle_client_text    (GodDrawingMsClientHandler *handler,
							 const guint8              *data,
							 GsfInput                  *input,
							 gsf_off_t                  length,
							 GError                   **err)
{
	TextParseState parse_state;

	parse_state.text_model = NULL;
	parse_state.handler = GOD_DRAWING_MS_CLIENT_HANDLER_PPT (handler);

	go_ms_parser_read (input,
			   length,
			   types,
			   (sizeof (types) / sizeof (types[0])),
			   &callbacks,
			   &parse_state,
			   NULL);
	return parse_state.text_model;
}

static GodAnchor *
god_drawing_ms_client_handler_ppt_handle_client_anchor    (GodDrawingMsClientHandler *handler,
							   const guint8              *data,
							   GsfInput                  *input,
							   gsf_off_t                  length,
							   GError                   **err)
{
	GodAnchor *anchor;
	GoRect rect;

	ERROR_RETVAL (length == 8, "Incorrect EscherClientAnchor", NULL);

	rect.top = GO_IN_TO_UN ((gint64)GSF_LE_GET_GUINT16 (data)) / 576;
	rect.left = GO_IN_TO_UN ((gint64)GSF_LE_GET_GUINT16 (data + 2)) / 576;
	rect.right = GO_IN_TO_UN ((gint64)GSF_LE_GET_GUINT16 (data + 4)) / 576;
	rect.bottom = GO_IN_TO_UN ((gint64)GSF_LE_GET_GUINT16 (data + 6)) / 576;

	anchor = god_anchor_new ();

	god_anchor_set_rect (anchor, &rect);

	return anchor;
}

#if 0
static GObject *
god_drawing_ms_client_handler_ppt_handle_client_data    (GodDrawingMsClientHandler *handler,
							 const guint8              *data,
							 GsfInput                  *input,
							 gsf_off_t                  length,
							 GError                    **err)
{
	return NULL;
}
#endif

static void
god_drawing_ms_client_handler_ppt_class_init (GodDrawingMsClientHandlerPptClass *class)
{
	GObjectClass *object_class;
	GodDrawingMsClientHandlerClass *handler_class;

	object_class                         = (GObjectClass *) class;
	handler_class                        = (GodDrawingMsClientHandlerClass *) class;

	domain                               = g_quark_from_static_string ("GodDrawingMsClientHandlerPpt");
	code                                 = 1;

	parent_class                         = g_type_class_peek_parent (class);

	object_class->finalize               = god_drawing_ms_client_handler_ppt_finalize;

	handler_class->handle_client_text    = god_drawing_ms_client_handler_ppt_handle_client_text;
	handler_class->handle_client_anchor  = god_drawing_ms_client_handler_ppt_handle_client_anchor;
#if 0
	handler_class->handle_client_data    = god_drawing_ms_client_handler_ppt_handle_client_data;
#endif

	handler_class->client_text_read_data = FALSE;
}

GSF_CLASS (GodDrawingMsClientHandlerPpt, god_drawing_ms_client_handler_ppt,
	   god_drawing_ms_client_handler_ppt_class_init, god_drawing_ms_client_handler_ppt_init,
	   GOD_DRAWING_MS_CLIENT_HANDLER_TYPE)


syntax highlighted by Code2HTML, v. 0.9.1