/*
 *  L3afpad - GTK+ based simple text editor
 *  Copyright (C) 2004-2007 Tarot Osuji
 *
 *  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.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <gtk/gtk.h>
#include "gtkprint.h"

static PangoLayout *layout;
static const PangoFontDescription *font_desc;
static gint line_count, lines_per_page, text_height;
static gint n_pages;
static gdouble page_width, page_height;
static const gchar *page_title = NULL;

static void get_tab_array(PangoTabArray **tabs,
	GtkPrintContext *ctx, GtkTextView *text_view)
{
	gint xft_dpi, loc;
	GtkSettings *settings = gtk_settings_get_default();

	g_object_get(settings, "gtk-xft-dpi", &xft_dpi, NULL);
	if ((*tabs = gtk_text_view_get_tabs(text_view))) {
		pango_tab_array_get_tab(*tabs, 0, NULL, &loc);
		pango_tab_array_set_tab(*tabs, 0, PANGO_TAB_LEFT,
			loc * gtk_print_context_get_dpi_x(ctx) / (xft_dpi / PANGO_SCALE));
	}
}

static void cb_begin_print(GtkPrintOperation *op,
		GtkPrintContext *ctx, gpointer data)
{
	gint layout_height;
	gchar *text;
	GtkTextIter start, end;
	GtkTextBuffer *buffer = gtk_text_view_get_buffer(data);
	PangoTabArray *tabs;

	gtk_text_buffer_get_bounds(buffer, &start, &end);
	text = g_strchomp(gtk_text_buffer_get_text(buffer, &start, &end, FALSE));

	page_width = gtk_print_context_get_width(ctx);
	page_height = gtk_print_context_get_height(ctx);
	font_desc = gtk_style_context_get_font(gtk_widget_get_style_context(data), GTK_STATE_FLAG_NORMAL);
	layout = gtk_print_context_create_pango_layout(ctx);
	pango_layout_set_width(layout, page_width * PANGO_SCALE);
	pango_layout_set_font_description(layout, font_desc);
	pango_layout_set_text(layout, text, -1);

	get_tab_array(&tabs, ctx, data);
	if (tabs) {
		pango_layout_set_tabs(layout, tabs);
		pango_tab_array_free(tabs);
	}
	pango_layout_get_size(layout, NULL, &layout_height);

	line_count = pango_layout_get_line_count(layout);
	text_height = pango_font_description_get_size(font_desc) / PANGO_SCALE;
	lines_per_page = page_height / text_height;

	n_pages = (line_count - 1) / lines_per_page + 1;
	gtk_print_operation_set_n_pages(op, n_pages);

	g_free(text);
}

static void cb_draw_page(GtkPrintOperation *op,
		GtkPrintContext *ctx, gint page_nr, gpointer data)
{
	cairo_t *cr;
	PangoLayoutLine *line;
	gint n_line, i, j = 0;

	PangoLayout *layout_lh, *layout_rh;
	gchar *page_text;
	gint layout_width;

	cr = gtk_print_context_get_cairo_context(ctx);

	layout_lh = gtk_print_context_create_pango_layout(ctx);
	pango_layout_set_font_description(layout_lh, font_desc);
	pango_layout_set_text(layout_lh, page_title, -1);
	cairo_move_to(cr, 0, - 72 / 25.4 * 10);
	pango_cairo_show_layout(cr, layout_lh);

	page_text = g_strdup_printf("%d / %d", page_nr + 1, n_pages);
	layout_rh = gtk_print_context_create_pango_layout(ctx);
	pango_layout_set_font_description(layout_rh, font_desc);
	pango_layout_set_text(layout_rh, page_text, -1);
//	pango_layout_set_alignment(layout_rh, PANGO_ALIGN_RIGHT);
	pango_layout_get_size(layout_rh, &layout_width, NULL);
	cairo_move_to(cr,
		page_width - layout_width / PANGO_SCALE, - 72 / 25.4 * 10);
	pango_cairo_show_layout(cr, layout_rh);
	g_free(page_text);

	if (line_count > lines_per_page * (page_nr + 1))
		n_line = lines_per_page * (page_nr + 1);
	else
		n_line = line_count;

	for (i = lines_per_page * page_nr; i < n_line; i++) {
		line = pango_layout_get_line(layout, i);
		cairo_move_to(cr, 0, text_height * (j + 1));
		pango_cairo_show_layout_line(cr, line);
		j++;
	}
}

static void cb_end_print(GtkPrintOperation *op,
		GtkPrintContext *ctx, gpointer data)
{
	g_object_unref(layout);
}

static GtkPrintSettings *settings = NULL;

static GtkPrintOperation *create_print_operation(GtkTextView *text_view)
{
	GtkPrintOperation *op;
	static GtkPageSetup *page_setup = NULL;

	op = gtk_print_operation_new();

	if (settings)
		gtk_print_operation_set_print_settings(op, settings);

	if (!page_setup) {
		page_setup = gtk_page_setup_new();
		gtk_page_setup_set_top_margin(page_setup, 25.0, GTK_UNIT_MM);
		gtk_page_setup_set_bottom_margin(page_setup, 20.0, GTK_UNIT_MM);
		gtk_page_setup_set_left_margin(page_setup, 20.0, GTK_UNIT_MM);
		gtk_page_setup_set_right_margin(page_setup, 20.0, GTK_UNIT_MM);
	}
	gtk_print_operation_set_default_page_setup(op, page_setup);

	g_signal_connect(op, "begin-print", G_CALLBACK(cb_begin_print), text_view);
	g_signal_connect(op, "draw-page", G_CALLBACK(cb_draw_page), NULL);
	g_signal_connect(op, "end-print", G_CALLBACK(cb_end_print), NULL);

	return op;
}

static void create_error_dialog(GtkTextView *text_view, gchar *message)
{
	GtkWidget *dialog;

	dialog = gtk_message_dialog_new(
		GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(text_view))),
		GTK_DIALOG_DESTROY_WITH_PARENT,
		GTK_MESSAGE_ERROR,
		GTK_BUTTONS_NONE,
		"%s", message);
	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
	gtk_dialog_add_buttons(GTK_DIALOG(dialog),
		GTK_STOCK_OK, GTK_RESPONSE_CANCEL, NULL);
	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}

void create_gtkprint_session(GtkTextView *text_view, const gchar *title)
{
	GtkPrintOperation *op;
	GtkPrintOperationResult res;
	GError *err = NULL;

	page_title = title;
	op = create_print_operation(text_view);

	res = gtk_print_operation_run(op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
		GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(text_view))), &err);
	switch (res) {
	case GTK_PRINT_OPERATION_RESULT_ERROR:
		create_error_dialog(text_view, err->message);
		g_error_free(err);
	case GTK_PRINT_OPERATION_RESULT_APPLY:
		if (settings)
			g_object_unref(settings);
		settings = g_object_ref(gtk_print_operation_get_print_settings(op));
	default:
		break;
	}

	g_object_unref(op);
}

void create_gtkprint_preview_session(GtkTextView *text_view, const gchar *title)
{
	GtkPrintOperation *op;
	GtkPrintOperationResult res;
	GError *err = NULL;

	page_title = title;
	op = create_print_operation(text_view);

	res = gtk_print_operation_run(op, GTK_PRINT_OPERATION_ACTION_PREVIEW,
		GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(text_view))), &err);
	if (res == GTK_PRINT_OPERATION_RESULT_ERROR) {
		create_error_dialog(text_view, err->message);
		g_error_free(err);
	}

	g_object_unref(op);
}
