/*
 * This file is part of Gnome Photo Printer.
 *
 * Gnome Photo Printer 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.
 *
 * Gnome Photo Printer 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 Gnome Photo Printer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <gnome.h>
#include <libgnome/gnome-i18n.h>
#include <glade/glade.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libgnomevfs/gnome-vfs.h>
#include <libgnomeprint/gnome-print.h>
#include <libgnomeprint/gnome-print-job.h>
#include <libgnomeprintui/gnome-print-dialog.h>
#include <glib/gprintf.h>
#include "gpp_print.h"
#include "gpp_functions.h"
#include "gpp_widget.h"
#include "gpp_callbacks.h"
#include "gpp.h"

/*
 * Prints the Pixbuf to the drawing area (Taken from libgnomeprint ->
 * examples
 */
void
gpp_print_pixbuf (GdkPixbuf * pixbuf)
{
	guchar *raw_image;
	gboolean has_alpha;
	gint rowstride, height, width;

	raw_image = gdk_pixbuf_get_pixels (pixbuf);
	has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
	height = gdk_pixbuf_get_height (pixbuf);
	width = gdk_pixbuf_get_width (pixbuf);

	if (has_alpha)
		gnome_print_rgbaimage (gpp_context, (char *) raw_image, width,
				       height, rowstride);
	else
		gnome_print_rgbimage (gpp_context, (char *) raw_image, width,
				      height, rowstride);
}

/*
 * Prints the Pictures
 */
void
gpp_print_pictures (gchar * name)
{
	GdkPixbuf *pixbuf;
	GError *error;
	gdouble scale_x, scale_y, shift;
	gchar *file_name;

	file_name = gnome_vfs_unescape_string (name, G_DIR_SEPARATOR_S);

	/*
	 * Load the image into a pixbuf
	 */
	error = NULL;
	pixbuf = gdk_pixbuf_new_from_file (file_name, &error);
	if (!pixbuf)
	{
		g_print ("Could not load %s.\n", file_name);
		return;
	}

	/*
	 * Rotate if nescassary
	 */
	if (((gpp_definition->layout_x < gpp_definition->layout_y)
	     && (gdk_pixbuf_get_width (pixbuf) >
		 gdk_pixbuf_get_height (pixbuf)))
	    || ((gpp_definition->layout_x > gpp_definition->layout_y)
		&& (gdk_pixbuf_get_width (pixbuf) <
		    gdk_pixbuf_get_height (pixbuf))))
		pixbuf = gpp_gdk_rotate_pixbuf_90 (pixbuf);

	/*
	 * Save the graphic context, scale, print the image and restore
	 */
	gnome_print_gsave (gpp_context);

	/*
	 * Scale to requested Size
	 */
	if (gpp_definition->image_scale_with_ratio)
	{
		scale_x =
			gdk_pixbuf_get_width (pixbuf) /
			gpp_definition->layout_x;
		scale_y =
			gdk_pixbuf_get_height (pixbuf) /
			gpp_definition->layout_y;
		if (scale_x >= scale_y)
                {
                        shift = gpp_definition->layout_y *(1.0 - scale_y / scale_x)/2.0;
                        /*
                         * Just for debugging g_printf ("shift: %g \n", shift);
                         */
                        gnome_print_translate (gpp_context, 0.0, shift);
			gnome_print_scale (gpp_context,
					   gpp_definition->layout_x,
					   gpp_definition->layout_y *
					   (scale_y / scale_x));
                }
		else
                {
                        shift = gpp_definition->layout_x *(1.0 - scale_x / scale_y)/2.0;
                        /*
                         * Just for debugging g_printf ("shift: %g \n", shift);
                         */
                        gnome_print_translate (gpp_context, shift, 0.0);
			gnome_print_scale (gpp_context,
					   gpp_definition->layout_x *
					   (scale_x / scale_y),
					   gpp_definition->layout_y);
                }
	}
	else
	{
		gnome_print_scale (gpp_context, gpp_definition->layout_x,
				   gpp_definition->layout_y);
	}

	/*
	 * Print to graphic context
	 */
	gpp_print_pixbuf (pixbuf);

	/*
	 * Restore the graphic context
	 */
	gnome_print_grestore (gpp_context);
	g_object_unref (G_OBJECT (pixbuf));
}

/*
 * Arranges the Pictures on a Page by given Layout
 */
void
gpp_arrange_pictures (GtkWidget * progress_bar)
{
	GtkTreeIter iter;
	GtkTreeModel *tree;
	gboolean valid, rotate;
	gint i, j, x, y, num_x, num_y, f = 0;
	gdouble space_x, space_y, pos_x = 0, pos_y = 0, old_pos_x = 0, old_pos_y = 0, progress = 0;

	/* check which orientation to favour */
	/* ...normal orientation */
	if (gpp_calculate_pics_on_page ()!=0)
                i = gpp_calculate_number_of_sites ();
	else
                i = -1;

	x = gpp_definition->layout_x;
	y = gpp_definition->layout_y;

	gpp_definition->layout_x = y;
	gpp_definition->layout_y = x;
	/* ...rotated 90 degrees */
	if (gpp_calculate_pics_on_page ()!=0)
	        j = gpp_calculate_number_of_sites ();
	else
                j = -1;

	/* page is too small! */
	if (i == -1 && j == -1)
        {
                g_printf("paper size is to small!\n");
                return;
	}

	/* take orientation, which is valid
	   and requires fewer pages */
	if (i == -1) rotate = 1;
	else if (j == -1) rotate = 0;
	else if ( i <= j ) rotate = 0;
	else rotate = 1;

 	if ( !rotate )
	{
	        rotate = 0;
		gpp_definition->layout_x = x;
		gpp_definition->layout_y = y;
	}

	tree = GTK_TREE_MODEL (gpp_definition->file_names);
	valid = gtk_tree_model_get_iter_first (tree, &iter);

	space_x =
		gpp_calculate_space_between_pics (gpp_definition->
						  paper_size_x,
						  gpp_definition->layout_x);
	space_y =
		gpp_calculate_space_between_pics (gpp_definition->
						  paper_size_y,
						  gpp_definition->layout_y);

	num_x = gpp_calculate_fit_to_page (gpp_definition->paper_size_x,
					   gpp_definition->layout_x);
	num_y = gpp_calculate_fit_to_page (gpp_definition->paper_size_y,
					   gpp_definition->layout_y);

	/*
	 * Just Debug Information to print on console g_printf ("Space X:
	 * %f\n", space_x); g_printf ("Space Y: %f\n", space_y); g_printf
	 * ("Number of Pages: %d\n", gpp_calculate_number_of_sites ());
	 * g_printf ("Pics on page: %d\n", gpp_calculate_pics_on_page ());
	 */

	/*
	 * Arrange the Pictures
	 */
	for (i = 0; i < gpp_calculate_number_of_sites (); i++)
	{
		gnome_print_beginpage (gpp_context, NULL);

		for (y = 0; y < num_y; y++)
		{
                        pos_y = y * (gpp_definition->layout_y + space_y) + space_y;
			for (x = 0; x < num_x; x++)
			{
				f++;
                                pos_x = x * (gpp_definition->layout_x + space_x) + space_x;
				/*
				 * Just for debugging g_printf ("X: %f, Y: %f \n", pos_x,
				 * pos_y);
				 */
				if (valid)
				{
					gchar *str_data;

					gnome_print_translate (gpp_context,
							       pos_x - old_pos_x, pos_y - old_pos_y);

					gtk_tree_model_get (tree, &iter,
							    FILE_COLUMN,
							    &str_data, -1);
					/*
					 * Just for debugging g_printf("File Names to print:
					 * %s",g_locale_from_utf8
					 * (str_data,-1,NULL,NULL,NULL));
					 */
					gtk_progress_bar_set_fraction
						(GTK_PROGRESS_BAR
						 (progress_bar),
						 progress /
						 gpp_definition->
						 number_of_files);
					progress++;

					gpp_print_pictures (str_data);

					while (g_main_context_iteration
					       (NULL, FALSE)) ;

					g_free (str_data);
					valid = gtk_tree_model_iter_next
						(tree, &iter);
                                        old_pos_x = pos_x;
                                        old_pos_y = pos_y;
				}
			}
		}
		pos_x = 0;
		pos_y = 0;
		old_pos_x = 0;
		old_pos_y = 0;
		f = 0;
		gnome_print_showpage (gpp_context);
	}

	if (rotate)
	{
	        x = gpp_definition->layout_x;
		gpp_definition->layout_x = gpp_definition->layout_y;
		gpp_definition->layout_y = x;
	}
}

/*
 * Starts Printing. FIXME soon as libgnomeprint gets fixed! Look at
 * gpp_get_settings_from_libgnomeprint () for getting a clue
 */
void
gpp_start_printing ()
{
	gnome_print_job_print_to_file (gpp_job,
				       gpp_definition->output_file_name);

	/*
	 * Should look this way! if (gpp_definition->to_file == TRUE) {
	 * g_printf ("Printing to File!\n"); gnome_print_job_print_to_file
	 * (gpp_job, gpp_definition-> output_file_name); } else { g_printf
	 * ("Printing to Printer!\n"); }
	 */

	gpp_start_printing_done ();
}

/*
 * Finishes Printing
 */
void
gpp_start_printing_done ()
{
	gnome_print_job_close (gpp_job);
	gnome_print_job_print (gpp_job);
	g_object_unref (G_OBJECT (gpp_context));
	g_object_unref (G_OBJECT (gpp_job));
}
