// -*- C++ -*-

/* 
 * Gnome Crystal
 * application.cc 
 *
 * Copyright (C) 2001-2007 Jean Bréfort <jean.brefort@normalesup.org>
 *
 * 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 <gtk/gtk.h>
#include <glade/glade.h>
#include <libgnomeprint/gnome-print.h>
#include <libgnomeprint/gnome-print-job.h>
#include <libgnomeprintui/gnome-print-dialog.h>
#include <libgnomeprintui/gnome-print-job-preview.h>
#include <libgnomevfs/gnome-vfs-ops.h>
#include <libgnomevfs/gnome-vfs-utils.h>
#include "application.h"
#include "globals.h"
#include <gcu/filechooser.h>
#include "prefs.h"
#include "window.h"
#include <glib/gi18n.h>
#include <cstring>

static unsigned short nNewDocs = 1;

gcApplication::gcApplication(): Application ("gcrystal")
{
}

gcApplication::~gcApplication ()
{
}

gcDocument *gcApplication::OnFileNew ()
{
	gcDocument* pDoc = new gcDocument (this);
	gchar buf[32];
	g_snprintf (buf, sizeof (buf), _("Untitled%d"), nNewDocs++);
	pDoc->SetTitle (buf);
	m_Docs.push_back (pDoc);
	new gcWindow (this, pDoc);
	return pDoc;
}

void gcApplication::OnFileOpen ()
{
	list<string> l;
	l.push_front ("application/x-gcrystal");
	FileChooser (this, false, l);
}

void gcApplication::OnFileSave ()
{
	if (!m_pActiveDoc)
		return;
	if (m_pActiveDoc->GetFileName ())
		m_pActiveDoc->Save ();
	else
		OnFileSaveAs ();
}

void gcApplication::OnFileSaveAs ()
{
	list<string> l;
	l.push_front ("application/x-gcrystal");
	FileChooser (this, true, l, m_pActiveDoc);
}

bool gcApplication::OnFileClose ()
{
	if (!m_pActiveDoc->VerifySaved ())
		return false;
	m_pActiveDoc->RemoveAllViews ();
	return true;
}

void gcApplication::OnFilePrint ()
{
	GnomePrintConfig* config = gnome_print_config_default ();
	GnomePrintContext *pc;
	GnomePrintJob *gpj = gnome_print_job_new (config);
	int do_preview = 0, copies = 1, collate = 0;
	GnomePrintDialog *gpd;
	gpd = GNOME_PRINT_DIALOG (gnome_print_dialog_new (gpj, (const guchar*) "Print test", GNOME_PRINT_DIALOG_COPIES));
	gtk_window_set_icon_name (GTK_WINDOW (gpd), "gcrystal");
	gnome_print_dialog_set_copies (gpd, copies, collate);
	switch (gtk_dialog_run (GTK_DIALOG (gpd))) {
	case GNOME_PRINT_DIALOG_RESPONSE_PRINT:
		do_preview = 0;
		break;
	case GNOME_PRINT_DIALOG_RESPONSE_PREVIEW:
		do_preview = 1;
		break;
	case GNOME_PRINT_DIALOG_RESPONSE_CANCEL:
		gtk_widget_destroy (GTK_WIDGET (gpd));
		return;
	}
	gtk_widget_destroy (GTK_WIDGET (gpd));
	pc = gnome_print_job_get_context (gpj);
	gnome_print_beginpage (pc, (const guchar*) "");
	gdouble width, height;
	gnome_print_config_get_double (config, (const guchar*) GNOME_PRINT_KEY_PAPER_WIDTH, &width);
	gnome_print_config_get_double (config, (const guchar*) GNOME_PRINT_KEY_PAPER_HEIGHT, &height);
	m_pActiveDoc->GetActiveView ()->Print (pc, width, height);
	gnome_print_showpage (pc);
	g_object_unref (pc);
	gnome_print_job_close (gpj);
	if (do_preview) {
		GtkWidget *preview = gnome_print_job_preview_new (gpj, (const guchar*)_("Preview"));
		gtk_window_set_icon_name (GTK_WINDOW (preview), "gcrystal");
		gtk_widget_show (preview);
	} else {
		gnome_print_job_print (gpj);
	}
	g_object_unref (gpj);
	gnome_print_config_unref (config);
}

void gcApplication::OnSaveAsImage ()
{
	if (!m_pActiveDoc)
		return;
	list<string> l;
	map<string, GdkPixbufFormat*>::iterator i, end = m_SupportedPixbufFormats.end ();
	for (i = m_SupportedPixbufFormats.begin (); i != end; i++)
		l.push_front ((*i).first.c_str ());
	l.push_front ("model/vrml");
	FileChooser (this, true, l, m_pActiveDoc, _("Save as image"), GetImageSizeWidget ());
}

gcDocument* gcApplication::GetDoc (const char* filename)
{
	gcDocument* pDoc = NULL;
	std::list<gcDocument*>::iterator i, iend = m_Docs.end ();
	for (i = m_Docs.begin (); i != iend; i++) {
		pDoc = *i;
		if (!pDoc->GetFileName ())
			continue;
		if (!strcmp (pDoc->GetFileName (), filename))
			break;
	}
	if (i != iend && pDoc)
		return pDoc;
	if (m_bFileOpening) {
		pDoc = m_Docs.back ();
		if (!pDoc->GetEmpty () || pDoc->GetDirty ())
			pDoc = NULL;
	}
	if (!pDoc) {
		OnFileNew ();
		pDoc = m_Docs.back ();
	}
	nNewDocs--;
	return pDoc;
}

enum {
	GCRYSTAL,
	VRML,
	PIXBUF
};

bool gcApplication::FileProcess (const gchar* filename, const gchar* mime_type, bool bSave, GtkWindow *window, Document *pDoc)
{
	gcDocument *Doc = static_cast<gcDocument*> (pDoc);
	if (!mime_type)
		mime_type = "application/x-gcrystal";
	string filename2 = filename;
	if (bSave) {
		int type = GCRYSTAL;
		char const *pixbuf_type = NULL;
		if (!strcmp (mime_type, "model/vrml"))
			type = VRML;
		else if ((pixbuf_type = GetPixbufTypeName (filename2, mime_type)))
			type = PIXBUF;
		char *ext = NULL;
		switch (type) {
		case GCRYSTAL:
			ext = (char*) ".gcrystal";
			break;
		case VRML:
			ext = (char*) ".wrl";
			break;
		default:
			break;
		}
		if (ext) { 
			int i = strlen (filename) - strlen (ext);
			if ((i <= 0) || (strcmp (filename +i, ext)))
				filename2 += ext;
		}
		GnomeVFSURI *uri = gnome_vfs_uri_new (filename2.c_str ());
		bool err = gnome_vfs_uri_exists (uri);
		gnome_vfs_uri_unref (uri);
		gint result = GTK_RESPONSE_YES;
		if (err) {
			gchar * message = g_strdup_printf (_("File %s\nexists, overwrite?"), filename2.c_str ());
			GtkDialog* Box = GTK_DIALOG (gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, message));
			gtk_window_set_icon_name (GTK_WINDOW (Box), "gcrystal");
			result = gtk_dialog_run (Box);
			gtk_widget_destroy (GTK_WIDGET (Box));
			g_free (message);
			if (result == GTK_RESPONSE_YES)
				gnome_vfs_unlink (filename2.c_str ());
		}
		map <string, string> options; // not used at the moment
		if (result == GTK_RESPONSE_YES)
			switch (type) {
			case GCRYSTAL:
				Doc->SetFileName (filename2);
				Doc->Save ();
				GtkRecentData data;
				data.display_name = (char*) Doc->GetTitle ();
				data.description = NULL;
				data.mime_type = (char*) "application/x-gcrystal";
				data.app_name = (char*) "gcrystal";
				data.app_exec = (char*) "gcrystal %u";
				data.groups = NULL;
				data.is_private =  FALSE;
				gtk_recent_manager_add_full (GetRecentManager (), filename2.c_str (), &data);
				Doc->RenameViews ();
				break;
			case VRML:
				Doc->OnExportVRML (filename2);
				break;
			case PIXBUF:
				Doc->SaveAsImage (filename2, pixbuf_type, options);
				break;
			}
	} else {
		if (strcmp (mime_type, "application/x-gcrystal"))
			return true;
		gcDocument *xDoc = GetDoc (filename);
		if (xDoc)
			Doc = xDoc;
		else if (!pDoc->GetEmpty () || pDoc->GetDirty ())
			Doc = NULL;
		if (!Doc)
			Doc = OnFileNew ();
		if (Doc->GetFileName () && !strcmp (Doc->GetFileName(), filename)) {
			if (!Doc->GetDirty ())
				return true;
			else {
				gchar* str = g_strdup_printf (_("\"%s\" has been modified since last saving. Do you wish to come back to saved version?"), Doc->GetTitle ());
				GtkWidget* mbox = gtk_message_dialog_new (window, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, str);
				int res = gtk_dialog_run (GTK_DIALOG (mbox));
				if (res != GTK_RESPONSE_YES)
					return true;
			}
		}
		if (Doc->Load (filename)) {
			GtkRecentData data;
			data.display_name = (char*) Doc->GetTitle ();
			data.description = NULL;
			data.mime_type = (char*) "application/x-gcrystal";
			data.app_name = (char*) "gcrystal";
			data.app_exec = (char*) "gcrystal %u";
			data.groups = NULL;
			data.is_private =  FALSE;
			gtk_recent_manager_add_full (GetRecentManager (), filename, &data);
			// change titles in every window and bring to front
			list <CrystalView *> *Views = Doc->GetViews ();
			list <CrystalView *>::iterator i, iend = Views->end ();
			int n = 1, max = Views->size ();
			char const *title = Doc->GetTitle ();
			for (i = Views->begin (); i != iend; i++) {
				gcWindow *window = dynamic_cast <gcView*> (*i)->GetWindow ();
				GtkWindow *w = window->GetWindow ();
				gtk_window_present (w);
				if (max > 1) {
					char *t = g_strdup_printf ("%s (%i)", title, n++);
					gtk_window_set_title (w, t);
					g_free (t);
				} else
					gtk_window_set_title (w, title);
				window->ActivateActionWidget ("ui/MainMenu/FileMenu/Save", !Doc->GetReadOnly ());
				window->ActivateActionWidget ("ui/MainToolbar/Save", !Doc->GetReadOnly ());
			}
		}
	}
	return false;
}

void gcApplication::RemoveDocument (gcDocument *pDoc)
{
	m_Docs.remove (pDoc);
	if (m_Docs.size () == 0)
		gtk_main_quit ();
}

bool gcApplication::OnQuit ()
{
	while (m_Docs.size () > 0) {
		m_pActiveDoc = m_Docs.front ();
		if (!OnFileClose ())
			return false;
	}
	return true;
}


syntax highlighted by Code2HTML, v. 0.9.1