// -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
//
//  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.
//

// Some codes are taken from Epiphany 0.8.2
// Copyright (C) 2000-2003 Marco Pesenti Gritti

// samples of nsISelection are:
//   content/base/src/nsDocumentViewer.cpp
//   layout/base/src/nsCaret.cpp


#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif /* HAVE_CONFIG_H */

#include "kz-mozwrapper.h"
#include <gtkmozembed_internal.h>

#include <stdlib.h>
#define MOZILLA_INTERNAL_API
#include <nsIServiceManager.h>
#undef MOZILLA_INTERNAL_API
#include <nsIInterfaceRequestorUtils.h>
#include <nsILocalFile.h>
#include <nsIDocShell.h>
#include <nsIDocShellTreeItem.h>
#include <nsIDocShellTreeOwner.h>
#include <nsIContentViewer.h>
#include <nsIDOMHTMLDocument.h>
#include <nsIDOMHTMLElement.h>
#include <nsIDOMHTMLImageElement.h>
#include <nsIDOMNSHTMLElement.h>  
#include <nsIDOMDocumentRange.h>
#include <nsIDOMNamedNodeMap.h>
#include <nsIDOMText.h>
#include <nsIDOMNodeList.h>
#include <nsIDOMNode.h>
#include <nsIClipboardCommands.h>
#define MOZILLA_STRICT_API
#include <nsEmbedString.h>
#undef MOZILLA_STRICT_API
#include <nsIDOMElement.h>
#include <nsIDOMDocumentType.h>
#include <nsIURI.h>
#include <nsIWebBrowserFocus.h>
#include <nsIWebPageDescriptor.h>
#include <nsIMarkupDocumentViewer.h>
#include <nsIDOMWindowInternal.h>
#include <nsIDOMWindowCollection.h>
#include <nsIDocShellHistory.h>
#include <nsIDocShellTreeNode.h>
#include <nsIScriptGlobalObject.h>
#include <nsISHistoryInternal.h>
#include <nsIHistoryEntry.h>
#include <nsICacheService.h>
#include <nsICacheSession.h>
#include <nsNetCID.h>
#include <nsIServiceManager.h>
#include <nsIOutputStream.h>
#include <nsIWebBrowserPrint.h>
#include <nsIPrintSettingsService.h>
#include <nsIPrintSettings.h>
#include <nsISupportsPrimitives.h>
#include <nsIDOM3Document.h>
#include <nsIDocCharset.h>
#include "kz-mozprogresslistener.h"
#include "kz-mozutils.h"
#include "utils.h"
#include "MozillaPrivate.h"
#include "kz-bookmark.h"

# include <nsISSLStatus.h>
# include <nsISSLStatusProvider.h>
# include <nsICertificateDialogs.h>
# include <nsIX509Cert.h>
# include <nsISecureBrowserUI.h>

KzMozWrapper::KzMozWrapper () :
	mWebBrowser (nsnull),
	mEventTarget (nsnull),
	mKzGeckoEmbed (nsnull),
	mKzMozEventListener (nsnull),
	mKzMozSelectionListener (nsnull),
	mSelectionWasCollapsed (PR_TRUE)
{
}


KzMozWrapper::~KzMozWrapper ()
{
}


nsresult
KzMozWrapper::Init (KzGeckoEmbed *kzembed)
{
	nsresult rv;
	
	mKzGeckoEmbed = kzembed;
	gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(mKzGeckoEmbed),
					getter_AddRefs(mWebBrowser));
	if (!mWebBrowser) return NS_ERROR_FAILURE;

	mWebBrowser->GetContentDOMWindow (getter_AddRefs (mDOMWindow));

	/* this codes was taken from Galeon-1.3.17 */
	/* This will instantiate an about:blank doc if necessary, but don't
	 * initialize for mozilla XUL dialogs, it breaks them */
	/* 
	 * 2004-09-19: removed the following codes 
	 *  because of inactivity of the gestures.
	 */ 
/*
	if (!(gtk_moz_embed_get_chrome_mask(GTK_MOZ_EMBED(kzembed)) &
	    GTK_MOZ_EMBED_FLAG_OPENASCHROME))
	{
		nsCOMPtr<nsIDOMDocument> domDocument;
		rv = mDOMWindow->GetDocument (getter_AddRefs(domDocument));
		if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
	}
*/

	mKzMozEventListener = new KzMozEventListener();
	rv = mKzMozEventListener->Init(kzembed);
	if (NS_FAILED (rv)) return NS_ERROR_FAILURE;
	GetListener();
	AttachListeners();
#if 0
	mKzMozSelectionListener = new KzMozSelectionListener;
	mKzMozSelectionListener->Init(kzembed);

	mKzMozHistoryListener = new KzMozHistoryListener();
	mKzMozHistoryListener->Init(kzembed);
	nsCOMPtr<nsIDocShell> DocShell;
	rv = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(rv) || !DocShell) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell,
								   &rv);
	if (!ContentNav) return NS_ERROR_FAILURE;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = ContentNav->GetSessionHistory(getter_AddRefs (SessionHistory));
	if (!SessionHistory) return NS_ERROR_FAILURE;
	rv = SessionHistory->AddSHistoryListener(mKzMozHistoryListener);

	//nsCOMPtr<nsIWeakReference> listener(do_GetWeakReference(NS_STATIC_CAST(nsISHistoryListener*, mKzMozHistoryListener)));
	//rv = mWebBrowser->AddWebBrowserListener(listener, NS_GET_IID(nsISHistoryListener));

	if (NS_FAILED (rv)) g_warning("failed to add a history listener");
#endif

// SSL related code
// These codes are picked from mozilla/GaleonWrapper in Galeon 1.3.21.
// Original copyright notice.
// Copyright (C) 2000 Marco Pesenti Gritti

#ifdef HAVE_NSIDOCSHELL_GETSECUREUI
	nsCOMPtr<nsIDocShell> docShell (do_GetInterface (mWebBrowser, &rv));
	NS_ENSURE_SUCCESS (rv, rv);

	rv = docShell->GetSecurityUI (getter_AddRefs (mSecurityInfo));
	NS_ENSURE_SUCCESS (rv, rv);
#else
	// Workaround for http://bugzilla.gnome.org/show_bug.cgi?id=164670
	mSecurityInfo = do_CreateInstance("@kazehakase.sf.jp/hacks/secure-browser-ui;1");
	if (mSecurityInfo)
	{
		mSecurityInfo->Init (mDOMWindow);
	}
	else
	{
		g_warning ("Failed to instantiate nsISecureBrowserUI!\n");
	}
#endif

	return NS_OK;
}


nsresult
KzMozWrapper::GetListener (void)
{
  	if (mEventTarget) return NS_ERROR_FAILURE;
	
  	nsCOMPtr<nsIDOMWindow> domWindowExternal;
  	mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindowExternal));
  
  	nsCOMPtr<nsIDOMWindow2> domWindow;
        domWindow = do_QueryInterface(domWindowExternal);
	if (!domWindow) return NS_ERROR_FAILURE;

	domWindow->GetWindowRoot(getter_AddRefs(mEventTarget));

	if (!mEventTarget) return NS_ERROR_FAILURE;

	return NS_OK;
}


nsresult
KzMozWrapper::AttachListeners(void)
{
  	if (!mEventTarget) return NS_ERROR_FAILURE;

	const PRUnichar domLiteral[] = { 'D', 'O', 'M', 'L', 'i', 'n', 'k',
	  				 'A', 'd', 'd', 'e', 'd', '\0' };
	return mEventTarget->AddEventListener(nsEmbedString(domLiteral),
				 	      mKzMozEventListener, PR_FALSE);
}


nsresult
KzMozWrapper::DetachListeners(void)
{
	if (!mEventTarget) return NS_ERROR_FAILURE;
	
	const PRUnichar domLiteral[] = { 'D', 'O', 'M', 'L', 'i', 'n', 'k',
	  				 'A', 'd', 'd', 'e', 'd', '\0' };
	return mEventTarget->RemoveEventListener(nsEmbedString(domLiteral),
					         mKzMozEventListener, PR_FALSE);
}


void
KzMozWrapper::Destroy (void)
{
	DetachListeners ();
	mKzGeckoEmbed = nsnull;
	mEventTarget = nsnull;
	mWebBrowser = nsnull;
}


//
// Our own methods
//

nsresult
KzMozWrapper::GetDocShell (nsIDocShell **aDocShell)
{
        if (!mWebBrowser) return NS_ERROR_FAILURE;

        nsCOMPtr<nsIDocShellTreeItem> browserAsItem;
        browserAsItem = do_QueryInterface(mWebBrowser);
        if (!browserAsItem) return NS_ERROR_FAILURE;

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

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

        // QI that back to a docshell
        nsCOMPtr<nsIDocShell> DocShell;
        DocShell = do_QueryInterface(contentItem);
        if (!DocShell) return NS_ERROR_FAILURE;

        *aDocShell = DocShell.get();
        NS_IF_ADDREF(*aDocShell);

        return NS_OK;
}


nsresult
KzMozWrapper::GetDocument (nsIDOMDocument **aDOMDocument)
{
	nsCOMPtr<nsIDOMDocument> domDocument;
	
	return mDOMWindow->GetDocument (aDOMDocument);
}


nsresult
KzMozWrapper::GetMainDomDocument (nsIDOMDocument **aDOMDocument)
{
        nsresult rv;

        nsCOMPtr<nsIDocShell> DocShell;
        rv = GetDocShell(getter_AddRefs(DocShell));
        if (NS_FAILED(rv) || !DocShell) return NS_ERROR_FAILURE;

        nsCOMPtr<nsIContentViewer> contentViewer;
        rv = DocShell->GetContentViewer(getter_AddRefs(contentViewer));
        if (!NS_SUCCEEDED(rv) || !contentViewer) return NS_ERROR_FAILURE;

        return contentViewer->GetDOMDocument(aDOMDocument);
}


nsresult
KzMozWrapper::GetDOMWindow (nsIDOMWindow **aDOMWindow)
{
	nsresult rv;
	
	rv = mWebBrowser->GetContentDOMWindow (aDOMWindow);
	
	return rv;
}


nsresult
KzMozWrapper::GetContentViewer (nsIContentViewer **aViewer)
{
        g_return_val_if_fail(mWebBrowser, NS_ERROR_FAILURE);

        nsCOMPtr<nsIDocShell> ourDocShell(do_GetInterface(mWebBrowser));
        NS_ENSURE_TRUE(ourDocShell, NS_ERROR_FAILURE);
        return ourDocShell->GetContentViewer(aViewer);
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::GetSHistory (nsISHistory **aSHistory)
{
	nsresult rv;

	nsCOMPtr<nsIDocShell> DocShell;
	rv = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(rv) || !DocShell) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIWebNavigation> ContentNav = do_QueryInterface (DocShell,
								   &rv);
	if (!ContentNav) return NS_ERROR_FAILURE;

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

	*aSHistory = SessionHistory.get();
	NS_IF_ADDREF (*aSHistory);

	return NS_OK;
}


nsresult
KzMozWrapper::GetSelection (nsISelection **selection)
{
	nsCOMPtr<nsIDOMWindow> domWindow;

	nsresult rv = GetFocusedDOMWindow (getter_AddRefs(domWindow));
	if (NS_FAILED(rv)) return NS_ERROR_FAILURE;

	return domWindow->GetSelection(selection);
}


nsresult
KzMozWrapper::GetHtmlWithContents (nsISelection *selection, 
			 	   const gchar *storedir,
				   nsAString &string)
{
	nsCOMPtr<nsIDOMRange> range;
	selection->GetRangeAt(0, getter_AddRefs(range));
	if (!range) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMDocument> domDoc;

	nsresult rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMNode> bodyNode;
	GetBodyNode(getter_AddRefs(bodyNode));
	
	SetHTMLHeadSource(domDoc, storedir, string);

	HTMLSourceFromNode(domDoc, bodyNode, selection, range, storedir, string);

	const PRUnichar end[] = { '\n', '<', '/', 'h', 't', 'm', 'l', '>', '\0' };
	string.Append(end);

	return NS_OK;
}


nsresult
KzMozWrapper::GetBodyString (nsAString &string)
{
	nsresult rv;
	nsCOMPtr<nsIDOMDocument> domDoc;
        rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMDocumentRange> docRange = do_QueryInterface(domDoc);
	if (!docRange)
		return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMRange> range;
	docRange->CreateRange(getter_AddRefs(range));
	if (!range)
		return NS_ERROR_FAILURE;

	MozillaPrivate::GetRootRange(domDoc, range);
	range->ToString(string);

	return NS_OK;
}


nsresult
KzMozWrapper::GetStringSelection (nsAString &string, gboolean backward)
{
	nsresult rv;
	nsCOMPtr<nsIDOMDocument> domDoc;
        rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;
	
	nsCOMPtr<nsIDOMDocumentRange> docRange = do_QueryInterface(domDoc);
	if (!docRange)
		return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMRange> range;
	docRange->CreateRange(getter_AddRefs(range));
	if (!range)
		return NS_ERROR_FAILURE;

	nsCOMPtr<nsISelection> selection;

	mDOMWindow->GetSelection(getter_AddRefs(selection));

	MozillaPrivate::GetSelectedRange(domDoc, range, selection, backward);

	range->ToString(string);

	return NS_OK;
}


nsresult
KzMozWrapper::CanCutSelection (PRBool *result)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->CanCutSelection(result);
}


nsresult 
KzMozWrapper::CanCopySelection (PRBool *result)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->CanCopySelection(result);
}


nsresult
KzMozWrapper::CanPaste (PRBool *result)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->CanPaste(result);
}


nsresult
KzMozWrapper::CutSelection (void)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->CutSelection();
}


nsresult
KzMozWrapper::CopySelection (void)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->CopySelection();
}


nsresult
KzMozWrapper::Paste (void)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	return clipboard->Paste();
}


nsresult
KzMozWrapper::SelectAll (void)
{
	nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
	
	return clipboard->SelectAll();
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::GetFocusedDOMWindow (nsIDOMWindow **aDOMWindow)
{
	nsresult rv;
	
	g_return_val_if_fail (mWebBrowser, NS_ERROR_FAILURE);

	nsCOMPtr<nsIWebBrowserFocus> focus = do_GetInterface(mWebBrowser, &rv);
	if (NS_FAILED(rv) || !focus) return NS_ERROR_FAILURE;

	rv = focus->GetFocusedWindow (aDOMWindow);
	if (NS_FAILED(rv))
		rv = mWebBrowser->GetContentDOMWindow (aDOMWindow);
	return rv;
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::GetWebNavigation (nsIWebNavigation **aWebNavigation)
{
	nsresult rv;

	nsCOMPtr<nsIDOMWindow> DOMWindow;
	rv = GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
	if (NS_FAILED(rv) || !DOMWindow) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIScriptGlobalObject> scriptGlobal = do_QueryInterface(DOMWindow);
	if (!scriptGlobal) return NS_ERROR_FAILURE;

	nsIDocShell *docshell = scriptGlobal->GetDocShell();
	if (!docshell)
		return NS_ERROR_FAILURE;
	
	nsCOMPtr<nsIWebNavigation> wn = do_QueryInterface (docshell, &rv);
	if (!wn || !NS_SUCCEEDED (rv)) return NS_ERROR_FAILURE;

	NS_IF_ADDREF(*aWebNavigation = wn);
	return NS_OK;
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::LoadDocument (nsISupports *aPageDescriptor,
			    PRUint32 aDisplayType)
{
	nsresult rv;

	nsCOMPtr<nsIWebNavigation> wn;
	rv = GetWebNavigation(getter_AddRefs(wn));
	if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv);
	if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;

	return wpd->LoadPage(aPageDescriptor, aDisplayType);
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::GetPageDescriptor (nsISupports **aPageDescriptor)
{
	nsresult rv;

	nsCOMPtr<nsIWebNavigation> wn;
	rv = GetWebNavigation(getter_AddRefs(wn));
	if (!wn || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIWebPageDescriptor> wpd = do_QueryInterface(wn, &rv);
	if (!wpd || !NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;

	return wpd->GetCurrentDescriptor(aPageDescriptor);
}


/* this function picked from galeon-1.3.11a. */
nsresult
KzMozWrapper::CopyHistoryTo (KzMozWrapper *dest, 
			     PRBool back_history, 
			     PRBool forward_history, 
			     PRBool set_current)
{
	nsresult rv;
	PRInt32 count, index;
	
	nsCOMPtr<nsISHistory> h_src;
	rv = GetSHistory (getter_AddRefs(h_src));
	if (NS_FAILED(rv) || !h_src) return NS_ERROR_FAILURE;

	h_src->GetCount (&count);
	h_src->GetIndex (&index);

	nsCOMPtr<nsISHistory> h_dest;
	rv = dest->GetSHistory (getter_AddRefs (h_dest));
	if (!NS_SUCCEEDED (rv) || (!h_dest)) return NS_ERROR_FAILURE;

	nsCOMPtr<nsISHistoryInternal> hi_dest = do_QueryInterface (h_dest);
	if (!hi_dest) return NS_ERROR_FAILURE;

	if (count) {
		nsCOMPtr<nsIHistoryEntry> he;
		nsCOMPtr<nsISHEntry> she;

		for (PRInt32 i = (back_history ? 0 : index + 1); 
		     i < (forward_history ? count : index + 1);
		     i++) 
		{

			rv = h_src->GetEntryAtIndex (i, PR_FALSE,
							 getter_AddRefs (he));
			if (!NS_SUCCEEDED(rv) || (!he))
				return NS_ERROR_FAILURE;

			she = do_QueryInterface (he);
			if (!she) return NS_ERROR_FAILURE;

			rv = hi_dest->AddEntry (she, PR_TRUE);
			if (!NS_SUCCEEDED(rv) || (!she))
				return NS_ERROR_FAILURE;
		}
		
		if (set_current)
		{
			nsCOMPtr<nsIDocShell> destDocShell;
			rv = dest->GetDocShell (getter_AddRefs(destDocShell));
			if (NS_FAILED(rv) || !destDocShell) return NS_ERROR_FAILURE;
		
			nsCOMPtr<nsIWebNavigation> wn_dest = do_QueryInterface (destDocShell, &rv);
			
			rv = wn_dest->GotoIndex(index);
			if (!NS_SUCCEEDED(rv)) return NS_ERROR_FAILURE;
		}
	}

	return NS_OK;
}


// picked from galeon-1.3.11a 
nsresult
KzMozWrapper::GetSHInfo (PRInt32 *count, PRInt32 *index)
{
	nsresult rv;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = GetSHistory (getter_AddRefs(SessionHistory));
	if (NS_FAILED(rv) || ! SessionHistory) return NS_ERROR_FAILURE;

	SessionHistory->GetCount (count);
	SessionHistory->GetIndex (index);	

	return NS_OK;
}


// picked from galeon-1.3.11a 
nsresult
KzMozWrapper::GetSHUrlAtIndex (PRInt32 index, nsACString &url)
{
	nsresult rv;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = GetSHistory (getter_AddRefs(SessionHistory));
	if (NS_FAILED(rv) || ! SessionHistory) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIHistoryEntry> he;
	rv = SessionHistory->GetEntryAtIndex (index, PR_FALSE,
					      getter_AddRefs (he));
	if (NS_FAILED(rv) || (!he)) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIURI> uri;
	rv = he->GetURI (getter_AddRefs(uri));
	if (NS_FAILED(rv) || (!uri)) return NS_ERROR_FAILURE;

	rv = uri->GetSpec(url);
	if (NS_FAILED(rv) || !url.Length()) return NS_ERROR_FAILURE;

	return NS_OK;
}

// picked from galeon-1.3.11a 
nsresult
KzMozWrapper::GetSHTitleAtIndex (PRInt32 index, PRUnichar **title)
{
	nsresult rv;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = GetSHistory (getter_AddRefs(SessionHistory));
	if (NS_FAILED(rv) || ! SessionHistory) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIHistoryEntry> he;
	rv = SessionHistory->GetEntryAtIndex (index, PR_FALSE,
						  getter_AddRefs (he));
	if (!NS_SUCCEEDED(rv) || (!he)) return NS_ERROR_FAILURE;

	rv = he->GetTitle (title);
	if (!NS_SUCCEEDED(rv) || (!title)) return NS_ERROR_FAILURE;

	return NS_OK;
}


nsresult
KzMozWrapper::GetHistoryEntry (PRInt32 index, nsIHistoryEntry **he)
{
	nsresult rv;

	nsCOMPtr<nsISHistory> SessionHistory;
	rv = GetSHistory (getter_AddRefs(SessionHistory));
	if (NS_FAILED(rv) || ! SessionHistory) return NS_ERROR_FAILURE;

	rv = SessionHistory->GetEntryAtIndex (index, PR_FALSE,
					      he);
	return rv;
}


nsresult 
KzMozWrapper::GoHistoryIndex (gint index)
{
	nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface (mWebBrowser);
	if (!nav) return NS_ERROR_FAILURE;

	return nav->GotoIndex (index);
}


nsresult
KzMozWrapper::GetDocumentUrl (nsACString &url)
{
	nsresult rv;
	nsCOMPtr<nsIDOMWindow> domWindow;
	nsCOMPtr<nsIDOMDocument> DOMDocument;

	mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));

	rv = domWindow->GetDocument(getter_AddRefs(DOMDocument));
	if (NS_FAILED(rv) || !DOMDocument) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOM3Document> doc = do_QueryInterface(DOMDocument);

	if(!doc) return NS_ERROR_FAILURE;

	nsEmbedString URI;
	doc->GetDocumentURI(URI);

	NS_UTF16ToCString(URI,
			  NS_CSTRING_ENCODING_UTF8, url);

	return NS_OK;
}


nsresult
KzMozWrapper::ForceEncoding (const char *encoding)
{
        nsresult rv;

        nsCOMPtr<nsIContentViewer> contentViewer;
        rv = GetContentViewer(getter_AddRefs(contentViewer));
        if (!NS_SUCCEEDED(rv) || !contentViewer) return NS_ERROR_FAILURE;

        nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer);
        if (!mdv) return NS_ERROR_FAILURE;

	rv = mdv->SetForceCharacterSet(nsEmbedCString(encoding));

        return rv;
}

/*
 * This function is derived from galeon-1.3.12(mozilla/GaleonWrapper.cpp).
 *  Copyright (C) 2000 Marco Pesenti Gritti
 */

nsresult 
KzMozWrapper::GetEncoding (char **encoding, PRBool &forced)
{
	nsCOMPtr<nsIDocCharset> docChar = do_GetInterface(mWebBrowser);
	char *charset;
	docChar->GetCharset(&charset);
	encoding = &charset;

	return NS_OK;
}


nsresult
KzMozWrapper::ResolveURI (nsIDOMDocument *domDoc,
			  const nsACString &origURI,
			  nsACString &URI)
{
        nsresult rv;

	nsCOMPtr<nsIDOM3Node> domnode = do_QueryInterface(domDoc);
     	if(!domnode) return NS_ERROR_FAILURE;
	
	nsEmbedString spec;
	domnode->GetBaseURI(spec);

	nsEmbedCString cSpec;
	NS_UTF16ToCString(spec,
			  NS_CSTRING_ENCODING_UTF8, cSpec);

	nsCOMPtr<nsIURI> baseURI;
	NewURI(getter_AddRefs(baseURI), cSpec.get());
	
	rv = baseURI->Resolve(origURI, URI);

	return rv;
}


void 
KzMozWrapper::SetAttributes (nsIDOMNode *node, 
			     nsIDOMDocument *domDoc,
			     nsAString &aString)
{
	const PRUnichar eq[] = { '=', '\0' };
	const PRUnichar dq[] = { '"', '\0' };
	const PRUnichar sp[] = { ' ', '\0' };
	
	nsCOMPtr<nsIDOMNamedNodeMap> attrs;
	node->GetAttributes(getter_AddRefs(attrs));
	if (!attrs) return;

	PRUint32 index, length;
	attrs->GetLength(&length);
	
	for (index = 0; index < length; index++)
	{
		nsCOMPtr<nsIDOMNode> attr;
		attrs->Item(index, getter_AddRefs(attr));
		nsEmbedString name, value;
		attr->GetNodeName(name);
		attr->GetNodeValue(value);
		value.Assign(nsEscapeHTML2(value.get(),
					   value.Length()));
			
		aString += sp;
		aString += name;
		aString += eq;
		aString += dq;
		aString += value;
		aString += dq;
	}
}

void
KzMozWrapper::SetStartTag (const nsAString &tag,
			   nsIDOMDocument *domDoc,
			   nsAString &aString)
{
	const PRUnichar lt[] = { '<', '\0' };
	const PRUnichar gt[] = { '>', '\0' };
	const PRUnichar cr[] = { '\n', '\0' };

	nsCOMPtr<nsIDOMNodeList> nodeList;
	domDoc->GetElementsByTagName(tag, getter_AddRefs(nodeList));
	
	if (!nodeList) return;

	PRUint32 index, length;
	nodeList->GetLength(&length);
	for (index = 0; index < length; index++)
	{
		nsCOMPtr<nsIDOMNode> child;
		nodeList->Item(index, getter_AddRefs(child));

		nsCOMPtr<nsIDOMElement> element;
		element = do_QueryInterface(child);
		if (!element) continue;
			
		nsEmbedString name;
		element->GetTagName(name);
		ToLowerCase(name);
		aString += lt;
		aString += name;
		SetAttributes(child, domDoc, aString);
		aString += gt;
		aString += cr;
	}
}

void
KzMozWrapper::SetHTMLHeadSource (nsIDOMDocument *domDocument,
				 const gchar *storedir,
			         nsAString &aSource)
{
	const PRUnichar dq[] = { '"', '\0' };
	const PRUnichar sp[] = { ' ', '\0' };
	const PRUnichar sl[] = { '/', '\0' };
	const PRUnichar lt[] = { '<', '\0' };
	const PRUnichar gt[] = { '>', '\0' };
	const PRUnichar cr[] = { '\n', '\0' };
	const PRUnichar dt[] = { '!', 'D', 'O', 'C', 'T', 'Y', 'P', 'E', '\0' };
	const PRUnichar head_c[] = {'h', 'e', 'a', 'd', '\0'};
	const PRUnichar htmlLiteral[] = {'h', 't', 'm', 'l', '\0'};
	
	nsCOMPtr<nsIDOMNode> domNode;
	domNode = do_QueryInterface(domDocument);

	// <!DOCTYPE name PUBLIC "PiblicId" "SystemId">
	nsCOMPtr<nsIDOMDocumentType> docType;
	domDocument->GetDoctype(getter_AddRefs(docType));
	
	if (docType)
	{
		nsEmbedString name, pubID, sysID;
		docType->GetName(name);
		docType->GetPublicId(pubID);
		docType->GetSystemId(sysID);
		aSource += lt;
		aSource += dt;
		aSource += sp;
		aSource += name;
		aSource += sp;
		aSource += sp;
		aSource += dq;
		aSource += pubID;
		aSource += dq;
		aSource += sp;
		aSource += dq;
		aSource += sysID;
		aSource += dq;
		aSource += gt;
		aSource += cr;
	}		   

	// html node <html ...>
	SetStartTag(nsEmbedString(htmlLiteral), domDocument, aSource);

	nsCOMPtr<nsIDOMNodeList> headList;
	domDocument->GetElementsByTagName(nsEmbedString(head_c),
					  getter_AddRefs(headList));
	if (!headList) return;

	PRUint32 length;
	headList->GetLength(&length);
	if (!length) return;

	nsCOMPtr<nsIDOMNode> head;
	headList->Item(0, getter_AddRefs(head));

	HTMLSourceFromNode(domDocument, head, nsnull, nsnull,
			   storedir, aSource);
}

void
KzMozWrapper::HTMLSourceFromNode(nsIDOMDocument *domDoc,
				 nsIDOMNode *node,
				 nsISelection *selection,
				 nsIDOMRange *range,
				 const gchar *storedir, 
				 nsAString &string)
{
	nsEmbedString tagname;
	nsEmbedCString cTagname;
	const PRUnichar dq[] = { '"', '\0' };
	const PRUnichar sp[] = { ' ', '\0' };
	const PRUnichar sl[] = { '/', '\0' };
	const PRUnichar lt[] = { '<', '\0' };
	const PRUnichar gt[] = { '>', '\0' };
	const PRUnichar eq[] = { '=', '\0' };

	PRBool contains;
	if (selection)
	{
		selection->ContainsNode(node, PR_TRUE, &contains);
		// if node is not contained in seletion, ignore.
		if(!contains)
			return;
	}

	nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
	if (element)
	{
		element->GetTagName(tagname);
		NS_UTF16ToCString(tagname,
				  NS_CSTRING_ENCODING_UTF8, cTagname);
		ToLowerCase(tagname);
		string += lt;
		string += tagname;
	
		char *relattr =  NULL;
		GetAttributeFromNode(node, "rel", &relattr);
				
		nsCOMPtr<nsIDOMNamedNodeMap> attrs;
		node->GetAttributes(getter_AddRefs(attrs));
		if (attrs)
		{
			PRUint32 index, length;
			attrs->GetLength(&length);
			for (index = 0; index < length; index++)
			{
				nsCOMPtr<nsIDOMNode> attr;
				attrs->Item(index, getter_AddRefs(attr));
				nsEmbedString name, value;
				attr->GetNodeName(name);
				attr->GetNodeValue(value);
			
				nsEmbedCString cName;
				NS_UTF16ToCString(name,
						  NS_CSTRING_ENCODING_UTF8,
						  cName);
				value.Assign(nsEscapeHTML2(value.get(),
							   value.Length()));
				
				nsEmbedCString cValue;
				NS_UTF16ToCString(value,
						  NS_CSTRING_ENCODING_UTF8,
						  cValue);
				string += sp;
				string += name;
				string += eq;

				// convert img src address to local file name
				if ((!g_ascii_strcasecmp(cTagname.get(), "img") && 
				     !g_ascii_strcasecmp(cName.get(), "src")) ||
				    (!g_ascii_strcasecmp(cName.get(), "background")))
				{
					nsEmbedCString curi; 
					nsEmbedString localfile;
					ResolveURI(domDoc, cValue, curi);

					GetFileToLocal(curi, storedir,
						       "images", localfile);
					
					string += dq;
					string += localfile;
					string += dq;
				}
				else if (!g_ascii_strcasecmp(cTagname.get(), "link") && 
				         !g_ascii_strcasecmp(cName.get(), "href") &&
					 relattr && 
					 !strcasecmp(relattr, "stylesheet"))
				{
					nsEmbedCString curi; 
					nsEmbedString localfile;
					ResolveURI(domDoc, cValue, curi);
					
					GetFileToLocal(curi, storedir,
						       "css", localfile);
					
					string += dq;
					string += localfile;
					string += dq;
				}
				else if (!g_ascii_strcasecmp(cTagname.get(), "a") && 
					 !g_ascii_strcasecmp(cName.get(), "href"))
				{
					nsEmbedCString curi;
					ResolveURI(domDoc, cValue, curi);

					nsEmbedString uri;
					NS_CStringToUTF16(curi,
							  NS_CSTRING_ENCODING_UTF8,
							  uri);
					string += dq;
					string += uri;
					string += dq;
				}
				else if (!g_ascii_strcasecmp(cTagname.get(), "meta") && 
					 !g_ascii_strcasecmp(cName.get(), "content"))
				{
					// change the encoding
					gchar *find, *start, *end;
					gchar *str = g_strdup(cValue.get());

					find = strstr(str, "charset=");

					if (find)
					{
						gint len;
						start = find + 8;
						end = strchr(start, ';');

						if (!end)
							len = strlen(start);
						else
							len = end - start;
						gchar *charset;
						charset = g_strndup(start, len);
						cValue.Assign(str, start - str);
						cValue.Append(charset);
						cValue.Append("UTF-8");
						if (end)
							cValue.Append(end);
						g_free(charset);
					}
					g_free(str);
					
					NS_CStringToUTF16(cValue,
							  NS_CSTRING_ENCODING_UTF8,
							  value);
					string += dq;
					string += value;
					string += dq;
				}
				else
				{
					string += dq;
					string += value;
					string += dq;
				}

			}
		}
		if (relattr) 
			g_free(relattr);
		// img,hr,br,input -> <img .. />,<hr />, <br />, <input .. /> 
		if (!g_ascii_strcasecmp(cTagname.get(), "img") ||
		    !g_ascii_strcasecmp(cTagname.get(), "hr") ||
		    !g_ascii_strcasecmp(cTagname.get(), "br") ||
		    !g_ascii_strcasecmp(cTagname.get(), "meta") ||
		    !g_ascii_strcasecmp(cTagname.get(), "link") ||
		    !g_ascii_strcasecmp(cTagname.get(), "input"))
		{
			string += sp;
			string += sl;
			string += gt;
		}
		else
			string += gt;
	}

	nsEmbedString text;
	nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(node);
	if (textNode) // if it's a text node, get the text
	{
		nsCOMPtr<nsIDOMNode> startNode;
		nsCOMPtr<nsIDOMNode> endNode;
		
		if (range)
		{
			range->GetStartContainer(getter_AddRefs(startNode));
			range->GetEndContainer(getter_AddRefs(endNode));
		
			if (node == startNode && node == endNode)
			{
				PRInt32 startOffset, endOffset;
				range->GetStartOffset(&startOffset);
				range->GetEndOffset(&endOffset);
				textNode->SubstringData(startOffset,
							endOffset-startOffset,
							text);
			}
			else if (node == startNode)
			{
				PRInt32 startOffset;
				PRUint32 strLength;
				textNode->GetLength(&strLength);
				range->GetStartOffset(&startOffset);
				textNode->SubstringData(startOffset,
							strLength-startOffset,
							text);
			}
			else if (node == endNode)
			{
				PRInt32 endOffset;
				range->GetEndOffset(&endOffset);
				textNode->SubstringData(0,
							endOffset,
							text);
			}
			else 
			{
				textNode->GetData(text);
			}
		}
		else 
		{
			textNode->GetData(text);
		}
		text.Assign(nsEscapeHTML2(text.get(),
					  text.Length()));
				
		string += text;
	}

	nsCOMPtr<nsIDOMNodeList> childNodeList;
	node->GetChildNodes(getter_AddRefs(childNodeList));
	if (childNodeList)
	{
		PRUint32 index, length;
		childNodeList->GetLength(&length);
		for (index = 0; index < length; index++)
		{
			nsCOMPtr<nsIDOMNode> child;
			childNodeList->Item(index, getter_AddRefs(child));
			
			if (selection)
				selection->ContainsNode(child, PR_TRUE, &contains);
			else 
				contains = PR_TRUE;
			if (contains)
			{
				HTMLSourceFromNode(domDoc,
						   child, 
						   selection,
						   range,
						   storedir, 
						   string);
			}
		}
	}

	if (element)
	{
		if (g_ascii_strcasecmp(cTagname.get(), "br") &&
		    g_ascii_strcasecmp(cTagname.get(), "hr") &&
		    g_ascii_strcasecmp(cTagname.get(), "input") &&
		    g_ascii_strcasecmp(cTagname.get(), "img") &&
		    g_ascii_strcasecmp(cTagname.get(), "meta") &&
		    g_ascii_strcasecmp(cTagname.get(), "link"))
		{
			string += lt;
			string += sl;
			string += tagname;
			string += gt;
		}
	}
}


// this function is picked from galeon-1.3.13
nsresult
KzMozWrapper::GetCacheEntryDescriptor(const nsACString &aKey,
				      nsICacheEntryDescriptor **aCacheEntryDescriptor)
{
	nsresult rv;

	nsCOMPtr<nsICacheService> cacheService =
		do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
	if (NS_FAILED(rv) || !cacheService) return NS_ERROR_FAILURE;


	nsCOMPtr<nsICacheSession> cacheSession;
	rv = cacheService->CreateSession("HTTP",
					 nsICache::STORE_ANYWHERE,
					 nsICache::STREAM_BASED,
					 getter_AddRefs(cacheSession));
	if(NS_FAILED(rv) || !cacheSession) return NS_ERROR_FAILURE;

	cacheSession->SetDoomEntriesIfExpired(PR_FALSE);
		
	nsCOMPtr<nsICacheEntryDescriptor> cacheEntryDescriptor;
#ifdef MOZ_NSICACHESESSION_NSACSTRING_
	rv = cacheSession->OpenCacheEntry(aKey,
					  nsICache::ACCESS_READ,
					  nsICache::NON_BLOCKING,
					  aCacheEntryDescriptor);
#else
	nsEmbedCString cKey(aKey);
	rv = cacheSession->OpenCacheEntry(cKey.get(),
					  nsICache::ACCESS_READ,
					  nsICache::NON_BLOCKING,
					  aCacheEntryDescriptor);
#endif

	if (NS_FAILED(rv) || !aCacheEntryDescriptor)
	{
		rv = cacheService->CreateSession("FTP",
						 nsICache::STORE_ANYWHERE,
						 nsICache::STREAM_BASED,
						 getter_AddRefs(cacheSession));
		if(NS_FAILED(rv) || !cacheSession) return NS_ERROR_FAILURE;

		cacheSession->SetDoomEntriesIfExpired (PR_FALSE);
#ifdef MOZ_NSICACHESESSION_NSACSTRING_
		return cacheSession->OpenCacheEntry(aKey,
					  nsICache::ACCESS_READ,
					  nsICache::NON_BLOCKING,
					  aCacheEntryDescriptor);
#else
		nsEmbedCString cKey(aKey);
		return cacheSession->OpenCacheEntry(cKey.get(),
					  nsICache::ACCESS_READ,
					  nsICache::NON_BLOCKING,
					  aCacheEntryDescriptor);
#endif
	}

	return NS_OK;
}


void
KzMozWrapper::GetFileToLocal (const nsACString &URI,
			      const gchar *storedir,
			      const gchar *type, 
			      nsAString &LocalFile)
{
	nsresult rv;
	nsEmbedCString sl("/");

	nsCOMPtr<nsICacheEntryDescriptor> cacheEntryDescriptor;
	rv = GetCacheEntryDescriptor(URI,
				     getter_AddRefs(cacheEntryDescriptor));

	if (NS_SUCCEEDED(rv) && cacheEntryDescriptor)
	{
		PRUint32 dataSize = 0;
		nsCOMPtr<nsIInputStream> inStream;

		gchar *dir, *buf;
		const gchar *uri;
		NS_CStringGetData(URI, &uri);
		gchar *filename = create_filename_from_uri(uri);

		dir = g_build_filename(g_get_home_dir(),
				       "."PACKAGE,
				       storedir,
				       type, /* images or css */ 
				       filename,
				       NULL);

		cacheEntryDescriptor->GetDataSize(&dataSize);
		cacheEntryDescriptor->OpenInputStream(0, getter_AddRefs(inStream));

		buf = g_new0(gchar, dataSize);

		inStream->Read(buf, dataSize, &rv);
		inStream->Close();
		
		nsEmbedCString cLocalFile;
		cLocalFile.Assign(type);
		cLocalFile += sl;
		cLocalFile.Append(filename);
		NS_CStringToUTF16(cLocalFile, 
				  NS_CSTRING_ENCODING_UTF8, LocalFile);

		nsCOMPtr<nsILocalFile> imageFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
		imageFile->InitWithNativePath(nsEmbedCString(dir));
		imageFile->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
		nsCOMPtr<nsIOutputStream> outStream;

		NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
					    imageFile,
					    -1,
					    0600);
		outStream->Write(buf, dataSize, &rv);
		outStream->Close();

		g_free(filename);
		g_free(dir);
		g_free(buf);
	}
}


nsresult
KzMozWrapper::Print (void)
{
	nsresult rv;
        nsCOMPtr<nsIPrintSettings> options;

	g_return_val_if_fail (mWebBrowser, NS_ERROR_FAILURE);

	nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv));
	if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE;

	print->GetGlobalPrintSettings(getter_AddRefs(options));
	options->SetPaperSize(nsIPrintSettings::kPaperSizeNativeData);
	options->SetPrintSilent(PR_FALSE);
	
//	KzMozProgressListener *aProgress = new KzMozProgressListener();
	rv = print->Print(options, nsnull);

	return rv;
}

nsresult
KzMozWrapper::PrintPreview (void)
{
	nsresult rv;
        nsCOMPtr<nsIPrintSettings> options;

	g_return_val_if_fail (mWebBrowser, NS_ERROR_FAILURE);

	nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser, &rv));
	if (NS_FAILED(rv) || !print) return NS_ERROR_FAILURE;

	print->GetGlobalPrintSettings(getter_AddRefs(options));
	options->SetPaperSize(nsIPrintSettings::kPaperSizeNativeData);
	rv = print->PrintPreview(options, mDOMWindow, nsnull);

	return rv;
}


nsresult
KzMozWrapper::GetPrinterList (GList **list)
{
	*list = MozillaPrivate::GetPrinterList();
	return NS_OK;
}

// these functions were picked from Galeon-1.3.17.

nsresult
KzMozWrapper::SetZoom (float aZoom, PRBool reflow)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	if (reflow)
	{
		nsCOMPtr<nsIContentViewer> contentViewer;	
		result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
		if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;

		nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer,
								  &result);
		if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE;

		return mdv->SetTextZoom (aZoom);
	}
	else
	{
		SetZoomOnDocshell (aZoom, DocShell);

		nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryInterface(DocShell));
		if (docShellNode)
		{
			PRInt32 i;
			PRInt32 n;
			docShellNode->GetChildCount(&n);
			for (i=0; i < n; i++) 
			{
				nsCOMPtr<nsIDocShellTreeItem> child;
				docShellNode->GetChildAt(i, getter_AddRefs(child));
				nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
				if (childAsShell) 
				{
					return SetZoomOnDocshell (aZoom, childAsShell);
				}
			}
		}
	}

	return NS_OK;
}

nsresult
KzMozWrapper::SetZoomOnDocshell (float aZoom, nsIDocShell *DocShell)
{
	gboolean ret = MozillaPrivate::SetZoomOnDocShell(aZoom, DocShell);

	if (!ret) return NS_ERROR_FAILURE;

	return NS_OK;
}

nsresult
KzMozWrapper::GetZoom (float *aZoom)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIContentViewer> contentViewer;	
	result = DocShell->GetContentViewer (getter_AddRefs(contentViewer));
	if (!NS_SUCCEEDED (result) || !contentViewer) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIMarkupDocumentViewer> mdv = do_QueryInterface(contentViewer,
								  &result);
	if (NS_FAILED(result) || !mdv) return NS_ERROR_FAILURE;

	return mdv->GetTextZoom (aZoom);
}

nsresult
KzMozWrapper::SetImageZoom (float aZoom)
{
	const PRUnichar imgLiteral[] = { 'i', 'm', 'g', '\0' };
	const PRUnichar styleLiteral[] = { 's', 't', 'y', 'l', 'e', '\0' };
	
	nsresult rv;
	nsCOMPtr<nsIDOMDocument> domDoc;
        rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMNodeList> nodeList;
	rv = domDoc->GetElementsByTagName(nsEmbedString(imgLiteral),
					  getter_AddRefs(nodeList));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;

	PRUint32 num;
	rv = nodeList->GetLength(&num);
	if (NS_FAILED(rv) || num < 1) return NS_ERROR_FAILURE;

	for (PRUint32 i = 0; i < num; i++)
	{
		nsCOMPtr<nsIDOMNode> node;
		rv = nodeList->Item(i, getter_AddRefs(node));
		if (NS_FAILED(rv) || !node) continue;
		nsCOMPtr<nsIDOMHTMLImageElement> img;
		img = do_QueryInterface(node);
		PRInt32 width = 0, height = 0;

		char *width_str =  NULL;
		GetAttributeFromNode(node, "width",
				     &width_str);
		if (!width_str) continue;

		if (str_isdigit(width_str))
			width = atoi(width_str);
		g_free(width_str);
		
		char *height_str =  NULL;
		GetAttributeFromNode(node, "height",
				     &height_str);
		if (!height_str) continue;
	
		if (str_isdigit(height_str))
			height = atoi(height_str);
		g_free(height_str);

		if (width == 0 || height == 0)
			continue;

		width = (PRInt32)(width * aZoom);
		height = (PRInt32)(height * aZoom);
		nsCOMPtr<nsIDOMElement> elm;
		elm = do_QueryInterface(node);
		nsEmbedString style_value;
		gchar *v;
		v = g_strdup_printf("width: %dpx; height: %dpx;",
				    width, height);
		nsEmbedCString cValue(v);
		NS_CStringToUTF16(cValue, NS_CSTRING_ENCODING_UTF8, style_value);
		elm->SetAttribute(nsEmbedString(styleLiteral), style_value);
		g_free(v);
	}
	
	return NS_OK;
}

nsresult
KzMozWrapper::GetDestAnchorsFromWindow (nsIDOMWindow *domWindow,
					GList **list)
{
	nsresult rv;
	gboolean flag = FALSE;
	const PRUnichar aLiteral[] = { 'a', '\0' };

	nsCOMPtr<nsIDOMDocument> domDoc;
	domWindow->GetDocument(getter_AddRefs(domDoc));

	nsCOMPtr<nsIDOMNodeList> nodeList;
	rv = domDoc->GetElementsByTagName(nsEmbedString(aLiteral),
			getter_AddRefs(nodeList));
	if (NS_FAILED(rv) || !nodeList) return NS_ERROR_FAILURE;

	PRUint32 num;
	rv = nodeList->GetLength(&num);
	if (NS_FAILED(rv) || num < 1) return NS_ERROR_FAILURE;

	nsEmbedCString docURL;
	GetDocumentUrl(docURL);

	// store links to GList
	nsCOMPtr<nsIDOMNode> node;
	for (PRUint32 i = 0; i < num; i++)
	{
		rv = nodeList->Item(i, getter_AddRefs(node));
		if (NS_FAILED(rv) || !node) continue;

		// check the node has name attribute or id attribure.
		char *value =  NULL;
		GetAttributeFromNode(node, "id", &value);
		if (!value)
			GetAttributeFromNode(node, "name", &value);
		if (!value)
			continue;

		nsEmbedCString cValue, cURI;
		cValue.Assign("#");
		cValue.Append(value, strlen(value));

		ResolveURI(domDoc, cValue, cURI);	
		g_free(value);

		KzBookmark *link;
		link = kz_bookmark_new_with_attrs(NULL, cURI.get(), NULL);
		*list = g_list_append(*list, link);

		flag = TRUE;
	}

	return flag ? NS_OK : NS_ERROR_FAILURE;
}


nsresult
KzMozWrapper::GetLinksFromWindow (nsIDOMWindow *domWindow,
				  GList **list,
				  nsISelection *selection, 
				  gboolean selected_only)
{
	nsresult rv;
	PRUint32 num = 0;
	gboolean flag = FALSE;
	const PRUnichar aLiteral[] = { 'a', '\0' };

        // get frame window
        nsCOMPtr<nsIDOMWindowCollection> frames;
        domWindow->GetFrames(getter_AddRefs(frames));

        if (frames)
	{
		frames->GetLength(&num);
	}

	if (num != 0)
	{
		for (PRUint32 i = 0; i < num; i++)
		{
			nsCOMPtr<nsIDOMWindow> childWindow;
	                frames->Item(i, getter_AddRefs(childWindow));
	                rv = GetLinksFromWindow(childWindow, list,
					        selection, selected_only);
	        	if (NS_SUCCEEDED(rv))
				flag |= TRUE;
		}
	}

	{
		nsCOMPtr<nsIDOMDocument> domDoc;
		domWindow->GetDocument(getter_AddRefs(domDoc));

		nsCOMPtr<nsIDOMNodeList> nodeList;
		rv = domDoc->GetElementsByTagName(nsEmbedString(aLiteral),
						  getter_AddRefs(nodeList));
	        if (NS_FAILED(rv) || !nodeList) return NS_ERROR_FAILURE;

		PRUint32 num;
		rv = nodeList->GetLength(&num);
		if (NS_FAILED(rv) || num < 1) return NS_ERROR_FAILURE;

		// store links to GList
		nsCOMPtr<nsIDOMNode> node;
		for (PRUint32 i = 0; i < num; i++)
		{
			rv = nodeList->Item(i, getter_AddRefs(node));
			if (NS_FAILED(rv) || !node) continue;

			// check whether the selection contains these nodes or not.
			if (selected_only)
			{
				PRBool contains;
				selection->ContainsNode(node, PR_TRUE, &contains);
				if (!contains) continue;
			}
			gchar *uri = NULL, *title = NULL;
			GetLinkAndTitleFromNode(domDoc, node,
					        &uri, &title);
			if (uri && *uri)
			{
				KzBookmark *link;
				link = kz_bookmark_new_with_attrs(title, uri, NULL);
				*list = g_list_append(*list, link);
			}
			g_free(uri);
			g_free(title);
			flag |= TRUE;
		}
	}

	return flag ? NS_OK : NS_ERROR_FAILURE;
}

nsresult 
KzMozWrapper::GetAttributeFromNode (nsIDOMNode *node, const char *attr, char **value)
{
     	nsresult result;

	nsCOMPtr<nsIDOMNamedNodeMap> attributes;
	result = node->GetAttributes(getter_AddRefs(attributes));
	if (!NS_SUCCEEDED (result) || !attributes) return NS_ERROR_FAILURE;

	nsEmbedString Attr;
	NS_CStringToUTF16(nsEmbedCString(attr), NS_CSTRING_ENCODING_UTF8, Attr);
	nsCOMPtr<nsIDOMNode> attrNode;
	result = attributes->GetNamedItem (Attr, getter_AddRefs(attrNode));
	if (!NS_SUCCEEDED(result) || !attrNode)  return NS_ERROR_FAILURE;

	nsEmbedString nodeValue;
	result = attrNode->GetNodeValue(nodeValue);
	if (!NS_SUCCEEDED(result))  return NS_ERROR_FAILURE;

	nsEmbedCString cNodeValue;
	NS_UTF16ToCString(nodeValue,
			  NS_CSTRING_ENCODING_UTF8, cNodeValue);
	*value = g_strdup(cNodeValue.get());

	return NS_OK;
}

nsresult
KzMozWrapper::GetLinkFromNode (nsIDOMDocument *domDoc, nsIDOMNode *node,
		               gchar **url)
{
	if (url) *url = NULL;

	// get url
	char *hrefattr =  NULL;
	GetAttributeFromNode(node, "href", &hrefattr);
	if (!hrefattr) return NS_ERROR_FAILURE;

	nsEmbedCString hrefc,linkc;
	hrefc.Assign(hrefattr);

	ResolveURI(domDoc, hrefc, linkc);

	*url = g_strdup(linkc.get());

	g_free(hrefattr);

	return NS_OK;
}

nsresult
KzMozWrapper::GetLinkAndTitleFromNode (nsIDOMDocument *domDoc, nsIDOMNode *node,
			               gchar **url, gchar **title)
{
	nsresult rv;
	const PRUnichar hrefLiteral[] = { 'h', 'r', 'e', 'f', '\0'};
	
	if (title) *title = NULL;
	if (url) *url = NULL;

	// get url
	GetLinkFromNode(domDoc, node, url);

	// get title
	nsCOMPtr<nsIDOMNamedNodeMap> attributes;
	node->GetAttributes(getter_AddRefs(attributes));

	nsCOMPtr<nsIDOMNode> hrefNode;
	attributes->GetNamedItem(nsEmbedString(hrefLiteral), getter_AddRefs(hrefNode));
	if (!hrefNode) return NS_ERROR_FAILURE;

	nsEmbedString linkhtml;
	nsCOMPtr<nsIDOMNSHTMLElement> nsElement;

	nsElement = do_QueryInterface(node);
	if (!nsElement) return NS_ERROR_FAILURE;

	rv = nsElement->GetInnerHTML(linkhtml);
	if (NS_SUCCEEDED(rv) && linkhtml.Length()) 
	{
		nsEmbedCString cLinkhtml;
		NS_UTF16ToCString(linkhtml,
				  NS_CSTRING_ENCODING_UTF8, cLinkhtml);
		*title = g_strdup(cLinkhtml.get());
	}

	return NS_OK;
}

nsresult
KzMozWrapper::GetPostData (nsIHistoryEntry *he, nsAString &postData)
{
	nsresult rv;

	nsCOMPtr<nsISHEntry> she = do_QueryInterface (he);

	nsCOMPtr<nsIInputStream> iStream;

	rv = she->GetPostData(getter_AddRefs(iStream));

	if (!iStream || NS_FAILED(rv)) return NS_ERROR_FAILURE;

	char *aBuf;
	PRUint32 aCount;
	PRUint32 ret;

	rv = iStream->Read(aBuf, 1024, &ret);

	g_warning("%s", aBuf);	

	return rv;
}	

nsresult
KzMozWrapper::SetPostData (nsIHistoryEntry *he, const nsAString &postData)
{
	nsresult rv;
#if 0
	nsCOMPtr<nsISHEntry> she = do_QueryInterface (he);

	nsCOMPtr<nsIInputStream> iStream;

	rv = NS_NewStringInputStream (getter_AddRefs(iStream), postData);
	if (!iStream || NS_FAILED(rv)) return NS_ERROR_FAILURE;

	rv = she->SetPostData(iStream);
#endif
	return rv;
}

// this function is picked from galeon-1.3.18
nsresult 
KzMozWrapper::FineScroll (int horiz, int vert)
{
	nsCOMPtr<nsIDOMWindow> DOMWindow;
	GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
	NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE);

	return DOMWindow->ScrollBy(horiz, vert);
}

nsresult 
KzMozWrapper::PageUp (void)
{
	nsCOMPtr<nsIDOMWindow> DOMWindow;
	GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
	NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE);

	return DOMWindow->ScrollByPages(-1);
}

nsresult 
KzMozWrapper::PageDown (void)
{
	nsCOMPtr<nsIDOMWindow> DOMWindow;
	GetFocusedDOMWindow (getter_AddRefs(DOMWindow));
	NS_ENSURE_TRUE (DOMWindow, NS_ERROR_FAILURE);

	return DOMWindow->ScrollByPages(1);
}

nsresult 
KzMozWrapper::AddSelectionListener (void)
{
	if (!mKzMozSelectionListener) return NS_ERROR_FAILURE;
	return mKzMozSelectionListener->AddSelectionListener();
}


nsresult 
KzMozWrapper::RemoveSelectionListener (void)
{
	if (!mKzMozSelectionListener) return NS_ERROR_FAILURE;
	return mKzMozSelectionListener->RemoveSelectionListener();
}


nsresult
KzMozWrapper::GetBodyNode (nsIDOMNode **bodyNode)
{
	nsCOMPtr<nsIDOMDocument> domDoc;
        nsresult rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;
	
	nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
	if (!htmlDoc) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMHTMLElement> bodyElement;
	htmlDoc->GetBody(getter_AddRefs(bodyElement));

	if (!bodyElement) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMNode> node;
	node = do_QueryInterface(bodyElement);

	NS_IF_ADDREF(*bodyNode = node);
	return NS_OK;
}

nsresult
KzMozWrapper::SetHighlightRange (nsIDOMRange **aSearchRange,
    				 nsIDOMRange **aStartRange,
				 nsIDOMRange **aEndRange)
{
	nsCOMPtr<nsIDOMDocument> domDoc;
        nsresult rv = GetMainDomDocument(getter_AddRefs(domDoc));
        if (NS_FAILED(rv) || !domDoc) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMNode> bodyNode;
	rv = GetBodyNode(getter_AddRefs(bodyNode));
        if (NS_FAILED(rv) || !bodyNode) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMNodeList> domNodeList;
	bodyNode->GetChildNodes(getter_AddRefs(domNodeList));
	if (!domNodeList) return NS_ERROR_FAILURE;

	PRUint32 length;
	domNodeList->GetLength(&length);
	
	nsCOMPtr<nsIDOMDocumentRange> docRange = do_QueryInterface(domDoc);
	if (!docRange) return NS_ERROR_FAILURE;

	nsCOMPtr<nsIDOMRange>searchRange;
	nsCOMPtr<nsIDOMRange>startRange;
	nsCOMPtr<nsIDOMRange>endRange;

	docRange->CreateRange(getter_AddRefs(searchRange));
	docRange->CreateRange(getter_AddRefs(startRange));
	docRange->CreateRange(getter_AddRefs(endRange));

	searchRange->SetStart(bodyNode, 0);
	searchRange->SetEnd(bodyNode, length);

	startRange->SetStart(bodyNode, 0);
	startRange->SetEnd(bodyNode, 0);

	endRange->SetStart(bodyNode, length);
	endRange->SetEnd(bodyNode, length);

	NS_IF_ADDREF(*aSearchRange = searchRange);
	NS_IF_ADDREF(*aStartRange = startRange);
	NS_IF_ADDREF(*aEndRange = endRange);
	return NS_OK;
}

nsresult
KzMozWrapper::GetAllowJavascript (PRBool *aAllow)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	return DocShell->GetAllowJavascript(aAllow);
}

nsresult
KzMozWrapper::SetAllowJavascript (PRBool aAllow)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	return DocShell->SetAllowJavascript(aAllow);
}

nsresult
KzMozWrapper::GetAllowImages (PRBool *aAllow)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	return DocShell->GetAllowImages(aAllow);
}

nsresult
KzMozWrapper::SetAllowImages (PRBool aAllow)
{
	nsresult result;

	nsCOMPtr<nsIDocShell> DocShell;
	result = GetDocShell (getter_AddRefs(DocShell));
	if (NS_FAILED(result) || !DocShell) return NS_ERROR_FAILURE;

	return DocShell->SetAllowImages(aAllow);
}


// SSL related code
// These codes are picked from mozilla/GaleonWrapper in Galeon 1.3.21.
// Original copyright notice.
// Copyright (C) 2000 Marco Pesenti Gritti
nsresult
KzMozWrapper::GetSSLStatus (nsISSLStatus **aSSLStatus)
{
	NS_ENSURE_TRUE (mSecurityInfo, NS_ERROR_FAILURE);

	nsCOMPtr<nsISSLStatusProvider> sp = do_QueryInterface (mSecurityInfo);
	NS_ENSURE_TRUE (sp, NS_ERROR_FAILURE);

	nsCOMPtr<nsISSLStatus> SSLStatus;
	sp->GetSSLStatus(getter_AddRefs(SSLStatus));
	NS_ENSURE_TRUE (SSLStatus, NS_ERROR_FAILURE);

	NS_ADDREF(*aSSLStatus = SSLStatus);
	return NS_OK;
}

nsresult
KzMozWrapper::ShowPageCertificate (void)
{
	nsresult rv;
	nsCOMPtr<nsISSLStatus> SSLStatus;
	GetSSLStatus (getter_AddRefs(SSLStatus));
	NS_ENSURE_TRUE (SSLStatus, NS_ERROR_FAILURE);

	nsCOMPtr<nsIX509Cert> serverCert;
	SSLStatus->GetServerCert (getter_AddRefs (serverCert));
	NS_ENSURE_TRUE (serverCert, NS_ERROR_FAILURE);

	nsCOMPtr<nsICertificateDialogs> certDialogs =
		do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv);
	NS_ENSURE_TRUE (certDialogs, NS_ERROR_FAILURE);

	return certDialogs->ViewCert (NULL, serverCert);
}

#ifdef MOZ_NSICANVASRENDERINGCONTEXTINTERNAL_HAVE_GETINPUTSTREAM_
nsresult
KzMozWrapper::CreateThumbnail (void)
{
	nsCOMPtr<nsIDOMWindow> domWindow;
	GetDOMWindow(getter_AddRefs(domWindow));
	
	nsEmbedCString sURI;
	GetDocumentUrl(sURI);
	const gchar *uri = sURI.get();
	
	if (!MozillaPrivate::CreateThumbnail(domWindow, uri))
		return NS_ERROR_FAILURE;

	return NS_OK;
}
#endif
