/*
 *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
 *
 *  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.
 *
 *  $Id: MozillaPrivate.cpp 2609 2006-09-14 05:25:45Z ikezoe $
 */

/*
 * Based on MozillaPrivate.cpp in Epiphany-1.5.1.
 *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
 */

#include "mozilla-config.h"

#include "config.h"
#include "kazehakase.h"

#include "MozillaPrivate.h"

#define MOZILLA_INTERNAL_API
#include <nsIServiceManager.h>
#include <nsIComponentManager.h>
#include <nsIPrintSettingsService.h>
#include <nsIPrintOptions.h>
#include <nsWeakPtr.h>
#include <nsPromiseFlatString.h>
#include <nsEscape.h>
#include <nsIDocument.h>
#ifdef MOZ_NSICANVASRENDERINGCONTEXTINTERNAL_HAVE_GETINPUTSTREAM_
#include <nsICanvasRenderingContextInternal.h>
#include <nsIDOMCanvasRenderingContext2D.h>
#endif
#undef MOZILLA_INTERNAL_API
#include <nsISimpleEnumerator.h>
#include <nsISupportsPrimitives.h>
#include <nsIContent.h>
#include <nsIDOMHTMLDocument.h>
#include <nsIDOMHTMLElement.h>
#include <nsIDOMHTMLImageElement.h>
#include <nsIWidget.h>
#include <nsPIDOMWindow.h>
#include <nsIChromeEventHandler.h>
#include <nsIDOMWindowInternal.h>
#include <nsIDOMDocument.h>
#ifdef HAVE_NSIPRESCONTEXT_H
#include <nsIPresContext.h>
#else
#include <nsPresContext.h>
#endif
#include <nsIDeviceContext.h>
#include <nsIMarkupDocumentViewer.h>
#include <nsIContentViewer.h>


/* IMPORTANT. Put only code that use internal mozilla strings (nsAutoString for
 * example) in this file. Note that you cannot use embed strings here,
 * the header inclusions will conflict.
 */

GList *
MozillaPrivate::GetPrinterList ()
{
	GList *printers = NULL;
	nsresult rv = NS_OK;

	nsCOMPtr<nsIPrintSettingsService> pss =
		do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
	NS_ENSURE_SUCCESS(rv, nsnull);

	nsCOMPtr<nsIPrintOptions> po = do_QueryInterface(pss, &rv);
	NS_ENSURE_SUCCESS(rv, nsnull);

	nsCOMPtr<nsISimpleEnumerator> avPrinters;
	rv = po->AvailablePrinters(getter_AddRefs(avPrinters));
	NS_ENSURE_SUCCESS(rv, nsnull);

	PRBool more = PR_FALSE;

	for (avPrinters->HasMoreElements(&more);
	     more == PR_TRUE;
	     avPrinters->HasMoreElements(&more))
	{
		nsCOMPtr<nsISupports> i;
		rv = avPrinters->GetNext(getter_AddRefs(i));
		NS_ENSURE_SUCCESS(rv, nsnull);

		nsCOMPtr<nsISupportsString> printer = do_QueryInterface(i, &rv);
		NS_ENSURE_SUCCESS(rv, nsnull);

		nsAutoString data;
		rv = printer->GetData(data);
		NS_ENSURE_SUCCESS(rv, nsnull);

		printers = g_list_prepend (printers, g_strdup (NS_ConvertUCS2toUTF8 (data).get()));
	}

	return g_list_reverse (printers);
}

gboolean
MozillaPrivate::CreatePrintSettings (nsIPrintSettings **options)
{
	nsCOMPtr<nsIPrintOptions> printService;
	printService = do_GetService("@mozilla.org/gfx/printsettings-service;1");
	
	if (!printService) return FALSE;

	nsresult rv = printService->CreatePrintSettings(options);
	if (NS_FAILED(rv)) return FALSE;

	return TRUE;
}

gboolean
MozillaPrivate::GetRootRange (nsIDOMDocument *domDoc, nsIDOMRange *range)
{
	nsCOMPtr<nsIContent> rootContent;
	nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
	if (htmlDoc)
	{
		nsCOMPtr<nsIDOMHTMLElement> bodyElement;
		htmlDoc->GetBody(getter_AddRefs(bodyElement));
		rootContent = do_QueryInterface(bodyElement);
	}

        // to avoid segfault with DetailedPreference, 
        // return if rootContent is NULL.
	if (!rootContent)
		return FALSE;

	nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootContent));

	PRUint32 childcount;
	childcount = rootContent->GetChildCount();
	
	range->SetStart(rootNode,0);
	range->SetEnd(rootNode,childcount);

	return TRUE;
}

gboolean
MozillaPrivate::GetSelectedRange (nsIDOMDocument *domDoc,
				  nsIDOMRange *range,
				  nsISelection *selection,
				  gboolean backward)
{
	nsCOMPtr<nsIContent> rootContent;
	nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
	if (htmlDoc)
	{
		nsCOMPtr<nsIDOMHTMLElement> bodyElement;
		htmlDoc->GetBody(getter_AddRefs(bodyElement));
		rootContent = do_QueryInterface(bodyElement);
	}

        // to avoid segfault with DetailedPreference, 
        // return if rootContent is NULL.
	if (!rootContent)
		return FALSE;

	// Get root content node
	nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootContent));

	PRUint32 childcount;
	childcount = rootContent->GetChildCount();
	
	if (backward)
	{
		if (selection)
		{
			nsCOMPtr<nsIDOMNode> endNode;
			PRInt32 endOffset;
			selection->CollapseToStart();
			selection->GetAnchorNode(getter_AddRefs(endNode));
			selection->GetAnchorOffset(&endOffset);
	
			range->SetEnd(endNode, endOffset);
		}
		else
		{
			range->SetEnd(rootNode, childcount);
		}
		range->SetStart(rootNode, 0);
	}
	else
	{
		if (selection)
		{
			nsCOMPtr<nsIDOMNode> endNode;
			PRInt32 endOffset;
			selection->GetAnchorNode(getter_AddRefs(endNode));
			selection->GetAnchorOffset(&endOffset);
	
			range->SetStart(endNode, endOffset + 1);
		}
		else
		{
			range->SetStart(rootNode, 0);
		}
		range->SetEnd(rootNode, childcount);
	}

	return TRUE;
}

gboolean
MozillaPrivate::SetZoomOnDocShell (float aZoom, nsIDocShell *DocShell)
{
#ifdef HAVE_NSIPRESCONTEXT_H
	nsCOMPtr<nsIPresContext> PresContext;
#else
	nsCOMPtr<nsPresContext> PresContext;
#endif
	nsresult rv = DocShell->GetPresContext (getter_AddRefs(PresContext));
	if (NS_FAILED(rv) || !PresContext) return FALSE;

	nsIDeviceContext *DeviceContext(nsnull);
	DeviceContext = PresContext->DeviceContext();
	if (!DeviceContext) return FALSE;

	nsCOMPtr<nsIContentViewer> ContentViewer;
	
	rv = DocShell->GetContentViewer(getter_AddRefs(ContentViewer));
	if (NS_FAILED(rv) || !ContentViewer) return FALSE;

	nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(ContentViewer);
	if (!mdv) return FALSE;

	rv = mdv->SetTextZoom (aZoom);

	if NS_FAILED(rv) return FALSE;
	
	return TRUE;
}

GdkWindow *
MozillaPrivate::GetGdkWindow (nsIBaseWindow *window)
{
  	nsCOMPtr<nsIWidget> mainWidget;
	window->GetMainWidget(getter_AddRefs(mainWidget));
	GdkWindow *gdk_window;
	gdk_window = NS_STATIC_CAST(GdkWindow *,
			  mainWidget->GetNativeData(NS_NATIVE_WINDOW));

	return gdk_window;
}

gboolean
MozillaPrivate::GetEventReceiver (nsIDOMWindow *domWindow, nsIDOMEventReceiver **receiver)
{
  	// get the private DOM window
	nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
  	// and the root window for that DOM window
  	nsCOMPtr<nsIDOMWindowInternal> rootWindow;
#ifndef MOZ_NSPIDOMWINDOW_RETURNNSPIDOMWINDOW_ 
	domWindowPrivate->GetPrivateRoot(getter_AddRefs(rootWindow));
#else
  	rootWindow = domWindowPrivate->GetPrivateRoot();
#endif
  
  	nsCOMPtr<nsPIDOMWindow> piWin;
	piWin = do_QueryInterface(rootWindow);

	nsCOMPtr<nsIChromeEventHandler> chromeHandler;
#ifndef MOZ_NSPIDOMWINDOW_RETURNNSPIDOMWINDOW_ 
	piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler));
#else
	chromeHandler = piWin->GetChromeEventHandler();
#endif
	nsCOMPtr<nsIDOMEventReceiver> er;
	er = do_QueryInterface(chromeHandler);

	*receiver = er;
	NS_ADDREF(*receiver);
	
  	return TRUE;
}

gchar *
MozillaPrivate::GetURIForDOMWindow(nsIDOMWindow* aDOMWindow)
{
	if (!aDOMWindow)
		return NULL;

	nsCOMPtr<nsIDOMDocument> domDoc;
	aDOMWindow->GetDocument(getter_AddRefs(domDoc));
	nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);

	if (!doc)
		return NULL;

	nsCOMPtr<nsIURI> uri;
	uri = doc->GetDocumentURI();

	nsCAutoString str;
	uri->GetHost(str);

	return g_strdup(str.get());
}

const char *
MozillaPrivate::Unescape(const char *text)
{
	return (const char*)nsUnescape((char*)text);
}

#ifdef MOZ_NSICANVASRENDERINGCONTEXTINTERNAL_HAVE_GETINPUTSTREAM_
#include "egg-pixbuf-thumbnail.h"
#define KZ_CANVAS_WIDTH 1024
#define KZ_CANVAS_HEIGHT 800
gboolean
MozillaPrivate::CreateThumbnail(nsIDOMWindow *domWindow, const gchar *uri)
{
	nsresult rv;
	nsCOMPtr<nsIDOMDocument> domDoc;
	domWindow->GetDocument(getter_AddRefs(domDoc));

	nsCOMPtr<nsICanvasRenderingContextInternal> context;

	nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=2d");
	context = do_CreateInstance(nsPromiseFlatCString(ctxString).get(), &rv);

	if (NS_FAILED(rv) || !context) return FALSE;

	context->SetDimensions(EGG_PIXBUF_THUMB_LARGE, KZ_THUMB_HEIGHT);
	context->SetCanvasElement(nsnull);

	nsCOMPtr<nsIDOMCanvasRenderingContext2D> domCanvas = do_QueryInterface(context, &rv);
	if (NS_FAILED(rv) || !domCanvas) return FALSE;

	float sx, sy;
	sx = (float) EGG_PIXBUF_THUMB_LARGE / KZ_CANVAS_WIDTH;
	sy = (float) KZ_THUMB_HEIGHT / KZ_CANVAS_HEIGHT;
	domCanvas->Scale(sx, sy);

	rv = domCanvas->DrawWindow(domWindow, 0, 0, KZ_CANVAS_WIDTH, KZ_CANVAS_HEIGHT, NS_LITERAL_STRING("rgb(0,0,0)")); 
	if (NS_FAILED(rv)) return FALSE;

	nsCOMPtr<nsIInputStream> imgStream;
	rv = context->GetInputStream(NS_LITERAL_CSTRING("image/png"), EmptyString(), getter_AddRefs(imgStream));
	if (NS_FAILED(rv) || !imgStream) return FALSE;

	// this code wa picked from content/html/content/src/nsHTMLCanvasElement.cpp in firefox-2.0b.
	PRUint32 bufSize;
	rv = imgStream->Available(&bufSize);
	if (NS_FAILED(rv)) return FALSE;

	bufSize += 16;
	PRUint32 imgSize = 0;
	char* imgData = (char*)g_malloc((gulong)bufSize);
	if (!imgData) return FALSE;

	PRUint32 numReadThisTime = 0;
	while ((rv = imgStream->Read(&imgData[imgSize], bufSize - imgSize,
					&numReadThisTime)) == NS_OK && numReadThisTime > 0)
	{
		imgSize += numReadThisTime;
		if (imgSize == bufSize)
		{
			// need a bigger buffer, just double
			bufSize *= 2;
			char* newImgData = (char*)g_realloc(imgData, (gulong)bufSize);
			if (!newImgData)
			{
				g_free(imgData);
				return FALSE;
			}
			imgData = newImgData;
		}
	}

	gchar *thumb_filename;
	thumb_filename = egg_pixbuf_get_thumb_filename(uri, EGG_PIXBUF_THUMB_LARGE);
	gboolean ret = g_file_set_contents(thumb_filename, imgData, imgSize, NULL);
		
	g_free(imgData);
	g_free(thumb_filename);
	
	return ret;
}
#endif
