// -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-

//
//  Copyright (C) 2002-2004 Hiroyuki Ikezoe
//  Copyright (C) 2003 Takuro Ashie
//
//  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, 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 "kz-mozthumbnailcreator.h"

#include <gtkmozembed.h>
#include <gtkmozembed_internal.h>
#include <glib/gi18n.h>

#include "kz-mozthumbnailprogress.h"
#include "gobject-utils.h"
#include "mozilla.h"
#include "utils.h"
#include "egg-pixbuf-thumbnail.h"

#include <nsCOMPtr.h>
#include <nsIDOMDocument.h>
#include <content/nsIDocumentViewer.h>
#include <content/nsIContent.h>
#include <nsIWebBrowser.h>
#include <content/nsIDocument.h>
#include <dom/nsIDOMNSDocument.h>
#include <docshell/nsIDocShell.h>
#include <nsIDOMWindow.h>
#include <necko/nsNetUtil.h>
#include <uconv/nsICharsetConverterManager.h>
#include <nsISHistory.h>
#include <nsIHistoryEntry.h>
#include <nsISHEntry.h>
#include <nsIWebNavigation.h>
#include <nsIWebBrowserPrint.h>
#include <nsIWebBrowserSetup.h>
#include <nsIPrintOptions.h>
#include <nsIPrintSettings.h>
#include <nsIPrintSettingsService.h>
#include <nsISHistoryInternal.h>
#include <docshell/nsIDocShellTreeItem.h>
#include <nsIDocShellTreeOwner.h>
#include <nsTime.h>

#include <nsCWebBrowser.h>
struct _KzMozThumbnailCreatorPriv
{
	nsCOMPtr<nsIWebBrowser> mWebBrowser;
	nsCOMPtr<nsISHistory> mHistory;
	gboolean is_creating;
};

static void kz_moz_thumbnail_creator_class_init    (KzMozThumbnailCreatorClass *klass);
static void kz_moz_thumbnail_creator_init          (KzMozThumbnailCreator *creator);
static void kz_moz_thumbnail_creator_destroy       (GtkObject *object);
static void kz_moz_thumbnail_creator_finalize      (GObject    *object);
static void kz_moz_thumbnail_creator_realize       (GtkWidget *widget);
static void kz_moz_thumbnail_creator_unrealize     (GtkWidget *widget);
static void kz_moz_thumbnail_creator_net_stop      (GtkMozEmbed *embed);

static void kz_moz_thumbnail_creator_create_thumbnail   (KzMozThumbnailCreator *kzembed, const gchar *uri);

static KzMozThumbnailCreator *creator_single = NULL;

static GtkMozEmbedClass *parent_class = NULL;

KZ_OBJECT_GET_TYPE(kz_moz_thumbnail_creator, "KzMozThumbnailCreator", KzMozThumbnailCreator,
		   kz_moz_thumbnail_creator_class_init, kz_moz_thumbnail_creator_init,
		   GTK_TYPE_MOZ_EMBED)


static void
kz_moz_thumbnail_creator_class_init (KzMozThumbnailCreatorClass *klass)
{
	GObjectClass *gobject_class;
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;
	GtkMozEmbedClass *moz_embed_class;

	parent_class    = (GtkMozEmbedClass *) g_type_class_peek_parent (klass);

	gobject_class   = (GObjectClass *) klass;
	object_class    = (GtkObjectClass *) klass;
	widget_class    = (GtkWidgetClass *) klass;
	moz_embed_class = (GtkMozEmbedClass *) klass;

	// GObject
	gobject_class->finalize = kz_moz_thumbnail_creator_finalize;

	// GtkObject signals
	object_class->destroy = kz_moz_thumbnail_creator_destroy;
 
	// widget class
	widget_class->realize         = kz_moz_thumbnail_creator_realize;
	widget_class->unrealize       = kz_moz_thumbnail_creator_unrealize;
 
	moz_embed_class->net_stop     = kz_moz_thumbnail_creator_net_stop;
}


static void
kz_moz_thumbnail_creator_init (KzMozThumbnailCreator *creator)
{
	// priv
	creator->priv = g_new0(KzMozThumbnailCreatorPriv, 1);
	creator->priv->is_creating = FALSE;
}

KzMozThumbnailCreator *
kz_moz_thumbnail_creator_new (void)
{
	KzMozThumbnailCreator *creator = KZ_MOZ_THUMBNAIL_CREATOR(g_object_new(KZ_TYPE_MOZ_THUMBNAIL_CREATOR, NULL));
	
	gtk_moz_embed_load_url(GTK_MOZ_EMBED(creator), "about:blank");
	return creator;
}

KzMozThumbnailCreator *
kz_moz_thumbnail_creator_get_instance (void)
{
	if (!creator_single)
		creator_single = kz_moz_thumbnail_creator_new();
	else
		g_object_ref(creator_single);

	return creator_single;
}

static void
kz_moz_thumbnail_creator_destroy (GtkObject *object)
{
	if (GTK_OBJECT_CLASS(parent_class)->destroy)
		GTK_OBJECT_CLASS(parent_class)->destroy(object);
}


KZ_OBJECT_FINALIZE (kz_moz_thumbnail_creator, KzMozThumbnailCreator)


static void
kz_moz_thumbnail_creator_realize (GtkWidget *widget)
{
	KzMozThumbnailCreator *creator = KZ_MOZ_THUMBNAIL_CREATOR(widget);
	if (GTK_WIDGET_CLASS(parent_class)->realize)
		GTK_WIDGET_CLASS(parent_class)->realize(widget);
	
	gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(widget),
					getter_AddRefs(creator->priv->mWebBrowser));
#if 0	
	nsCOMPtr<nsIWebBrowserSetup> setup;
	setup = do_QueryInterface(creator->priv->mWebBrowser);
	setup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_PLUGINS, PR_FALSE);
#endif
}


static void
kz_moz_thumbnail_creator_unrealize (GtkWidget *widget)
{
	KzMozThumbnailCreator *creator = KZ_MOZ_THUMBNAIL_CREATOR(widget);

	if (GTK_WIDGET_CLASS(parent_class)->unrealize)
		GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
}


typedef struct _SiteInfo
{
	KzMozThumbnailCreator *creator;
	gchar *uri;
} SiteInfo;

static gboolean
idle_create_thumbnail (gpointer data)
{
	SiteInfo *info = (SiteInfo*)data;

	KzMozThumbnailCreator *creator = KZ_MOZ_THUMBNAIL_CREATOR(info->creator);

	kz_moz_thumbnail_creator_create_thumbnail(creator, 
						  info->uri);
	
	g_free(info->uri);
	g_free(info);
	return FALSE;
}

static void
net_stop_proccess (KzMozThumbnailCreator *creator)
{
        nsCOMPtr<nsIDocShellTreeItem> browserAsItem;
        browserAsItem = do_QueryInterface(creator->priv->mWebBrowser);
        if (!browserAsItem) return;

        // get the owner for that item
        nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
        browserAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
        if (!treeOwner) return;

        // get the primary content shell as an item
        nsCOMPtr<nsIDocShellTreeItem> contentItem;
        treeOwner->GetPrimaryContentShell(getter_AddRefs(contentItem));
        if (!contentItem) return;

        // QI that back to a docshell
        nsCOMPtr<nsIDocShell> DocShell;
        DocShell = do_QueryInterface(contentItem);
	
        nsCOMPtr<nsIContentViewer> contentViewer;
        nsresult rv = DocShell->GetContentViewer(getter_AddRefs(contentViewer));
        if (!NS_SUCCEEDED(rv) || !contentViewer) return;

	nsCOMPtr<nsIDOMDocument> domDoc;
        contentViewer->GetDOMDocument(getter_AddRefs(domDoc));

	//get the last modification time
	nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(domDoc);
	nsAutoString value;
	nsDoc->GetLastModified(value);
	nsTime lm (NS_ConvertUCS2toUTF8(value).get(), PR_TRUE);
	GTime last_modified;
	LL_DIV(last_modified,
	       NS_STATIC_CAST(PRTime, lm), PR_USEC_PER_SEC);

	nsCOMPtr<nsIURI> inURI;
	nsCAutoString sURI;

	nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
	if(!doc) return; 

#if MOZILLA_SNAPSHOT > 12
	nsIURI *uri;
	uri = doc->GetDocumentURI();
#else
	nsIURI *uri;
	uri = doc->GetDocumentURL();
#endif

	rv =  uri->GetSpec(sURI);
      	rv = NS_NewURI(getter_AddRefs(inURI), sURI);

	if (sURI.Equals("about:blank"))
		return;

	gchar *guri = ToNewCString(sURI);

	if ((!last_modified || (thumbnail_get_last_modified(guri) < last_modified)))
	{
		SiteInfo *info = g_new0(SiteInfo, 1);
		info->creator = creator;
		info->uri = g_strdup(guri);
		g_idle_add(idle_create_thumbnail, (gpointer)info);
	}

	g_free(guri);
}


static void
kz_moz_thumbnail_creator_net_stop (GtkMozEmbed *embed)
{
	KzMozThumbnailCreator *creator = KZ_MOZ_THUMBNAIL_CREATOR(embed);

	g_return_if_fail(KZ_IS_MOZ_THUMBNAIL_CREATOR(creator));

	if (parent_class->net_stop)
		parent_class->net_stop(embed);

	net_stop_proccess(creator);
}

static void
kz_moz_thumbnail_creator_create_thumbnail (KzMozThumbnailCreator *creator, const gchar *uri)
{
	nsresult rv;
	nsCOMPtr<nsIPrintSettings> options;

	nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(creator->priv->mWebBrowser, &rv));
	if (NS_FAILED(rv) || !print)
	{
		creator->priv->is_creating = FALSE;
		return;
	}
	nsCOMPtr<nsIPrintOptions> printService;
	printService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
	if (!printService) 
	{
		creator->priv->is_creating = FALSE;
		return;
	}

//	nsCOMPtr<nsIPrintSettingsService> printSettingsService;
//	printSettingsService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
//	if (!printSettingsService) return;
	
//	printSettingsService->GetNewPrintSettings(getter_AddRefs(options));

	printService->CreatePrintSettings(getter_AddRefs(options));
	
	gchar *thumb_filename;
	thumb_filename = egg_pixbuf_get_thumb_filename(uri,
						       EGG_PIXBUF_THUMB_LARGE);
	gchar *ps_name;	
	ps_name = g_strconcat(thumb_filename, ".ps", NULL);
	g_free(thumb_filename);

	options->SetPrintRange(nsIPrintSettings::kRangeSpecifiedPageRange);
	options->SetStartPageRange(1);
	options->SetEndPageRange(1);
	options->SetMarginTop(0.0);
	options->SetMarginLeft(0.0);
	options->SetMarginBottom(0.0);
	options->SetMarginRight(0.0);
	options->SetPrinterName(NS_LITERAL_STRING("PostScript/default").get());
	options->SetHeaderStrLeft(NS_LITERAL_STRING("").get());
	options->SetHeaderStrCenter(NS_LITERAL_STRING("").get());
	options->SetHeaderStrRight(NS_LITERAL_STRING("").get());
	options->SetFooterStrLeft(NS_LITERAL_STRING("").get());
	options->SetFooterStrCenter(NS_LITERAL_STRING("").get());
	options->SetFooterStrRight(NS_LITERAL_STRING("").get());
	options->SetPaperSize(nsIPrintSettings::kPaperSizeNativeData);
	options->SetPaperName(NS_LITERAL_STRING("Letter").get());
	options->SetToFileName(NS_ConvertUTF8toUCS2(ps_name).get());
	options->SetPrintToFile(PR_TRUE);	
	options->SetPrintInColor(PR_TRUE);
	options->SetOrientation(nsIPrintSettings::kLandscapeOrientation);
	options->SetPrintBGImages(PR_TRUE);
	options->SetPrintBGColors(PR_TRUE);
	options->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
	options->SetShowPrintProgress(PR_FALSE);
	options->SetShrinkToFit(PR_TRUE);
	options->SetNumCopies(1);
	options->SetPrintSilent(PR_TRUE);

	PRBool printing = PR_TRUE;

//	print->ExitPrintPreview();
	/* it is dangerous. */
	while (printing)
	{
		print->GetDoingPrintPreview(&printing);
		if (!printing)
			break;

		while (gtk_events_pending())
			gtk_main_iteration();
	}

	KzMozThumbnailProgressListener *aProgress = new KzMozThumbnailProgressListener(ps_name, creator);
	rv = print->Print(options, aProgress);
	g_free(ps_name);
}

void
kz_moz_thumbnail_creator_create_next (KzMozThumbnailCreator *creator)
{
	g_return_if_fail(KZ_IS_MOZ_THUMBNAIL_CREATOR(creator));

	nsresult rv;
        if (!creator->priv->mWebBrowser) return;
	
	nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (creator->priv->mWebBrowser,
								   &rv);
	if (!ContentNav) return;

	gtk_moz_embed_stop_load(GTK_MOZ_EMBED(creator));

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = ContentNav->GetSessionHistory (getter_AddRefs (SessionHistory));

	PRInt32 count, index;
	SessionHistory->GetCount (&count);
	SessionHistory->GetIndex (&index);	

	// remove previous page
	if (count > 2)
		SessionHistory->PurgeHistory(index);
	
	PRBool exist_next;
	ContentNav->GetCanGoForward(&exist_next);

	if (exist_next)
		ContentNav->GoForward();
	else
	{
		creator->priv->is_creating = FALSE;
		gtk_moz_embed_load_url(GTK_MOZ_EMBED(creator), "about:blank");
	}
}

void
kz_moz_thumbnail_creator_append_queue (KzMozThumbnailCreator *creator,
				       gpointer data)
{
	g_return_if_fail(KZ_IS_MOZ_THUMBNAIL_CREATOR(creator));
	nsresult rv;
        if (!creator->priv->mWebBrowser) return;
	
	nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (creator->priv->mWebBrowser,
								   &rv);
	if (!ContentNav) return;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = ContentNav->GetSessionHistory (getter_AddRefs (SessionHistory));
	nsCOMPtr<nsISHistoryInternal> hi = do_QueryInterface (SessionHistory);
	if (!hi) return;

	nsIHistoryEntry *he = (nsIHistoryEntry*) data;
	nsCOMPtr<nsISHEntry> she = do_QueryInterface (he);
	if (!she) return;
	
	nsCOMPtr<nsISHEntry> dest_she;
	she->Clone(getter_AddRefs(dest_she));
	
	rv = hi->AddEntry (dest_she, PR_TRUE);
	if (NS_FAILED(rv)) return;

	if (creator->priv->is_creating) return;

	creator->priv->is_creating = TRUE;

	PRInt32 index;
	SessionHistory->GetIndex (&index);	
	ContentNav->GotoIndex(index);
}

