/* dia-export-print.c
 * Copyright (C) 2002  Nik Kim <fafhrd@datacom.kz>, Arjan Molenaar
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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 "dia-export-print.h"
#include "dia-canvas-groupable.h"

#ifndef DIACANVAS2_HAS_GNOME_PRINT

void 
dia_export_print (gpointer gpm, DiaCanvas *canvas)
{
}

#else /* !DIACANVAS2_HAS_GNOME_PRINT */

#include <libgnomeprint/gnome-print.h>
#include <libgnomeprint/gnome-print-job.h>
#include <libgnomeprint/gnome-print-config.h>
#include <libart_lgpl/art_vpath.h>
#include <libart_lgpl/art_affine.h>
#include <pango/pango-layout.h>

/* used by print_path() to set the currentpath. Somehow using
 * gnome_print_vpath() doesn't give the desired result. */
static inline void
_print_path(ArtVpath *vpath, GnomePrintContext *context)
{
	gnome_print_newpath (context);
	while (vpath->code != ART_END) {
		switch (vpath->code) {
		case ART_MOVETO:
			gnome_print_moveto (context, vpath->x, vpath->y);
			break;
		case ART_LINETO:
			gnome_print_lineto (context, vpath->x, vpath->y);
			break;
		default:
			break;
		}
		vpath++;
	}
}

static void
print_path (DiaShapePath *shape, GnomePrintContext *context)
{
	if (!shape->vpath || shape->vpath->code == ART_END)
		return;

	/* First define the fill shape */
	if (shape->fill != DIA_FILL_NONE
	    && DIA_COLOR_ALPHA (shape->fill_color) > 0) {
		_print_path (shape->vpath, context);
		gnome_print_setrgbcolor (context,
			((gdouble) DIA_COLOR_RED (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_GREEN (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_BLUE (shape->fill_color)) /255.0);
		gnome_print_setopacity (context,
			((gdouble) DIA_COLOR_ALPHA (shape->fill_color)) /255.0);
		gnome_print_eofill (context);
	}

	_print_path (shape->vpath, context);
	if (shape->cyclic)
		gnome_print_closepath(context);

	gnome_print_setrgbcolor (context,
		((gdouble) DIA_COLOR_RED (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_GREEN (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_BLUE (shape->shape.color)) /255.0);
	gnome_print_setopacity (context,
		((gdouble) DIA_COLOR_ALPHA (shape->shape.color)) / 255.0);

	gnome_print_setlinewidth (context, shape->line_width);
	gnome_print_setlinejoin (context, shape->join);
	gnome_print_setlinecap (context, shape->cap);
	gnome_print_stroke (context);
}

static void
print_bezier (DiaShapeBezier *shape, GnomePrintContext *context)
{
	if (!shape->bpath || shape->bpath->code == ART_END)
		return;


	if (shape->fill != DIA_FILL_NONE
	    && DIA_COLOR_ALPHA (shape->fill_color) > 0) {
		gnome_print_setrgbcolor (context,
			((gdouble) DIA_COLOR_RED (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_GREEN (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_BLUE (shape->fill_color)) /255.0);
		gnome_print_setopacity (context,
			((gdouble) DIA_COLOR_ALPHA (shape->fill_color)) /255.0);
		gnome_print_bpath (context, shape->bpath, FALSE);
		gnome_print_eofill (context);
	}

	gnome_print_setrgbcolor (context,
		((gdouble) DIA_COLOR_RED (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_GREEN (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_BLUE (shape->shape.color)) /255.0);
	gnome_print_setopacity (context,
		((gdouble) DIA_COLOR_ALPHA (shape->shape.color)) / 255.0);

	gnome_print_setlinewidth (context, shape->line_width);
	gnome_print_setlinejoin (context, shape->join);
	gnome_print_setlinecap (context, shape->cap);
	gnome_print_newpath (context);
	gnome_print_bpath (context, shape->bpath, FALSE);
	if (shape->cyclic)
		gnome_print_closepath(context);

	gnome_print_stroke (context);
}

static void
print_ellipse (DiaShapeEllipse *shape, GnomePrintContext *context)
{
	gdouble r = 0.0, zoom;

	if (shape->height > shape->width) {
		r = shape->height;
		zoom = shape->width/shape->height;
		gnome_print_translate (context, shape->center.y-shape->center.y*zoom,0);
		gnome_print_scale (context, zoom, 1);
	} else {
		r = shape->width;
		zoom = shape->height/shape->width;
		gnome_print_translate (context, 0,shape->center.x-shape->center.x*zoom);
		gnome_print_scale (context, 1, zoom);
	}

	if (shape->fill != DIA_FILL_NONE
	    && DIA_COLOR_ALPHA (shape->fill_color) > 0) {
		gnome_print_setrgbcolor (context,
			((gdouble) DIA_COLOR_RED (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_GREEN (shape->fill_color)) /255.0,
			((gdouble) DIA_COLOR_BLUE (shape->fill_color)) /255.0);
		gnome_print_setopacity (context,
			((gdouble) DIA_COLOR_ALPHA (shape->fill_color)) /255.0);
		gnome_print_arcto (context, shape->center.x, shape->center.y,
				   r/2,0,359,0);
		gnome_print_fill (context);
	}

	gnome_print_setrgbcolor (context,
		((gdouble) DIA_COLOR_RED (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_GREEN (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_BLUE (shape->shape.color)) /255.0);
	gnome_print_setopacity (context,
		((gdouble) DIA_COLOR_ALPHA (shape->shape.color)) / 255.0);

	gnome_print_setlinewidth (context, shape->line_width);

	gnome_print_arcto (context, shape->center.x, shape->center.y, r/2,0,359,0);
	gnome_print_stroke (context);
}

static void
print_text (DiaShapeText *shape, GnomePrintContext *context)
{
	GnomeFont *font;
	GnomeFontFace *font_face;
	PangoFontDescription *font_desc;
	PangoLayout *layout = dia_shape_text_to_pango_layout ((DiaShape *)shape, TRUE);
	PangoLayoutLine *line;
	PangoLayoutIter *layout_iter;
	PangoRectangle irect, lrect;
	guchar *line_text;

	PangoStyle style;
	gboolean italic;

	if (!shape->text)
		return;

	gnome_print_concat (context, shape->affine);

	/* Set up a clipping rectangle */
	if (shape->max_width < G_MAXINT && shape->max_height < G_MAXINT) {
		gnome_print_newpath (context);
		gnome_print_moveto (context, 0.0, 0.0);
		gnome_print_lineto (context, (gdouble) shape->max_width, 0.0);
		gnome_print_lineto (context, (gdouble) shape->max_width,
				    (gdouble) shape->max_height);
		gnome_print_lineto (context, 0.0, (gdouble) shape->max_height);
		gnome_print_clip (context);
	}

	gnome_print_setrgbcolor (context,
		((gdouble) DIA_COLOR_RED (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_GREEN (shape->shape.color)) /255.0,
		((gdouble) DIA_COLOR_BLUE (shape->shape.color)) /255.0);
	gnome_print_setopacity (context,
		((gdouble) DIA_COLOR_ALPHA (shape->shape.color)) / 255.0);

	/* set context font */
	if (shape->font_desc)
		font_desc = shape->font_desc;
	else
		font_desc = pango_context_get_font_description (
				pango_layout_get_context (layout));

	style = pango_font_description_get_style (font_desc);
	italic = ((style == PANGO_STYLE_OBLIQUE) || 
		  (style == PANGO_STYLE_ITALIC));

	font_face = gnome_font_face_find_closest_from_weight_slant (
			pango_font_description_get_family (font_desc), 
			pango_font_description_get_weight (font_desc), 
			italic);
	font = gnome_font_face_get_font_default (
			font_face, 
			(pango_font_description_get_size (font_desc)/PANGO_SCALE+8/3));
	gnome_print_setfont (context, font);

	/* iterate on lines*/
	layout_iter = pango_layout_get_iter (layout);
	if (layout_iter) do {
		line = pango_layout_iter_get_line (layout_iter);
		pango_layout_iter_get_line_extents (layout_iter, &irect, &lrect);
	
		gnome_print_gsave (context);

		line_text = g_malloc0(line->length+1);
		g_strlcpy (line_text, &(shape->text[line->start_index]),line->length+1);

		//gnome_print_translate (context, 0, (lrect.height-irect.y)/PANGO_SCALE);
		gnome_print_moveto (context, ((gdouble)irect.x)/PANGO_SCALE, ((gdouble)irect.y + lrect.height/2)/PANGO_SCALE);
		gnome_print_scale (context, 1, -1);
		gnome_print_show (context, line_text);

		gnome_print_grestore (context);
		g_free (line_text);

	} while (pango_layout_iter_next_line (layout_iter));
	pango_layout_iter_free (layout_iter);

	g_object_unref (font);
	g_object_unref (font_face);
	g_object_unref (layout);
}

static void
print_image (DiaShapeImage *shape, GnomePrintContext *context)
{
	if (!shape->pixbuf)
		return;

	gnome_print_concat (context, shape->affine);
	gnome_print_translate (context, 0.0, (gdouble) gdk_pixbuf_get_height (shape->pixbuf));
	gnome_print_scale (context,
			   (gdouble) gdk_pixbuf_get_width (shape->pixbuf),
			   (gdouble) -gdk_pixbuf_get_height (shape->pixbuf));
	gnome_print_setopacity (context, 1.0);
	gnome_print_rgbaimage (context,
			       gdk_pixbuf_get_pixels (shape->pixbuf),
			       gdk_pixbuf_get_width (shape->pixbuf),
			       gdk_pixbuf_get_height (shape->pixbuf),
			       gdk_pixbuf_get_rowstride (shape->pixbuf));
}

static void
print_item (DiaCanvasItem *item, GnomePrintContext *context)
{
	DiaCanvasIter iter;
	DiaShape *shape;

	gnome_print_gsave (context);
	gnome_print_concat (context, item->affine);

	if (dia_canvas_item_get_shape_iter (item, &iter)) do {
		shape = dia_canvas_item_shape_value (item, &iter);

		if (shape->visibility != DIA_SHAPE_VISIBLE)
			continue;

		gnome_print_gsave (context);
		switch (shape->type) {
		case DIA_SHAPE_PATH:
			print_path ((DiaShapePath *)shape, context);
			break;
		case DIA_SHAPE_BEZIER:
			print_bezier ((DiaShapeBezier *)shape, context);
			break;
		case DIA_SHAPE_ELLIPSE:
			print_ellipse ((DiaShapeEllipse *)shape, context);
			break;
		case DIA_SHAPE_TEXT:
			print_text ((DiaShapeText *)shape, context);
			break;
		case DIA_SHAPE_IMAGE:
			print_image ((DiaShapeImage *)shape, context);
			break;
		case DIA_SHAPE_WIDGET:
			g_message (__FUNCTION__": Widget not yet implemented.");
			break;
		case DIA_SHAPE_CLIP:
			g_message (__FUNCTION__": Clip not yet implemented.");
			break;
		default:
			g_message ("Shape with type %d is not (yet) implemented", shape->type);
			break;
		}
		gnome_print_grestore (context);

	} while (dia_canvas_item_shape_next (item, &iter));

	if (DIA_IS_CANVAS_GROUPABLE (item) && 
	    dia_canvas_groupable_get_iter (DIA_CANVAS_GROUPABLE (item), &iter)) do {
		print_item (dia_canvas_groupable_value (DIA_CANVAS_GROUPABLE (item), &iter), context);
	} while (dia_canvas_groupable_next (DIA_CANVAS_GROUPABLE (item), &iter));
    
	gnome_print_grestore (context);
}

void 
dia_export_print (GnomePrintJob *gpm, DiaCanvas *canvas)
{
	gboolean old_state_requests;
	GnomePrintConfig *config = gnome_print_job_get_config (gpm);
	GnomePrintContext *context = gnome_print_job_get_context (gpm);
	gdouble height = 29.7 * (72.0 / 2.54);
	gdouble affine[6] = {1, 0, 0, -1, 0, height};
	const GnomePrintUnit *unit;

	// calc page height in pt
	if (gnome_print_config_get_length (
		config, GNOME_PRINT_KEY_PAPER_HEIGHT, &height, &unit)) {
		gnome_print_convert_distance (&height, unit,
					      GNOME_PRINT_PS_UNIT);
		affine[5] = height;
	}

	gnome_print_gsave (context);
	gnome_print_concat (context, affine);

	/* Disable state requests... */
	old_state_requests = canvas->allow_state_requests;
	g_object_set (canvas, "allow-state-requests", FALSE, NULL);

	print_item (canvas->root, context);

	g_object_set (canvas, "allow-state-requests", old_state_requests ? TRUE : FALSE, NULL);

	gnome_print_grestore (context);
}

#endif /* DIACANVAS2_HAS_GNOME_PRINT */
