// -*- 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


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

#include <xpcom/nsIInterfaceRequestorUtils.h>
#include <docshell/nsIDocShell.h>
#include <docshell/nsIDocShellTreeItem.h>
#include <docshell/nsIDocShellTreeOwner.h>
#include <docshell/nsIContentViewer.h>
#include <nsIClipboardCommands.h>
#include <nsLiteralString.h>
#include <nsString.h>
#include <nsIDOMElement.h>
#include <nsIDocument.h>
#include <nsIURI.h>
#include <nsIWebBrowserFocus.h>
#include <nsIWebPageDescriptor.h>
#include <nsUnicharUtils.h>
#include <nsIMarkupDocumentViewer.h>
#include <nsIDOMWindowInternal.h>
#include <nsIChromeEventHandler.h>
#include <nsIDocShellHistory.h>
#include <nsIScriptGlobalObject.h>
#include <nsISHistoryInternal.h>
#include <nsIHistoryEntry.h>

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

KzMozWrapper::KzMozWrapper () :
	mWebBrowser (nsnull),
	mKzMozEmbed (nsnull),
	mKzMozEventListener (nsnull),
	mEventReceiver (nsnull),
	mSelectionWasCollapsed (PR_TRUE)
{
}


KzMozWrapper::~KzMozWrapper ()
{
}


nsresult
KzMozWrapper::Init (KzMozEmbed *kzembed)
{
	nsresult rv;

	mKzMozEmbed = kzembed;
	gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(mKzMozEmbed),
					getter_AddRefs(mWebBrowser));
	if (!mWebBrowser) return NS_ERROR_FAILURE;

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

	nsCOMPtr<nsIDocShellHistory> dsHistory = do_QueryInterface (DocShell);
	if (!dsHistory) return NS_ERROR_FAILURE;

	mWebBrowser->GetContentDOMWindow (getter_AddRefs (mDOMWindow));

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

	return NS_OK;
}


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

  	nsCOMPtr<nsIChromeEventHandler> chromeHandler;
  	piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler));

  	mEventReceiver = do_QueryInterface(chromeHandler);
	if (!mEventReceiver) return NS_ERROR_FAILURE;

	return NS_OK;
}


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

	nsCOMPtr<nsIDOMEventTarget> target;
	target = do_QueryInterface (mEventReceiver);

	return target->AddEventListener(NS_LITERAL_STRING("DOMLinkAdded"),
			                mKzMozEventListener, PR_FALSE);
}


nsresult
KzMozWrapper::DetachListeners(void)
{
	if (!mEventReceiver) return NS_ERROR_FAILURE;
	
	nsCOMPtr<nsIDOMEventTarget> target;
	target = do_QueryInterface (mEventReceiver);

	return target->RemoveEventListener(NS_LITERAL_STRING("DOMLinkAdded"),
					   mKzMozEventListener, PR_FALSE);
}


void
KzMozWrapper::Destroy (void)
{
	DetachListeners ();
	mKzMozEmbed = 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 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;

        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 result;

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

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

	nsCOMPtr<nsISHistory> SessionHistory;
	result = 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)
{
	if (!mDOMWindow) return NS_ERROR_FAILURE;
	return mDOMWindow->GetSelection(selection);
}


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 result;

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

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

	nsCOMPtr<nsIDocShell> docshell;
	if (NS_FAILED(scriptGlobal->GetDocShell(getter_AddRefs(docshell))))
        return NS_ERROR_FAILURE;

	nsCOMPtr<nsIWebNavigation> wn = do_QueryInterface (docshell, &result);
	if (!wn || !NS_SUCCEEDED (result)) 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 result;
	PRInt32 count, index;
	
	nsCOMPtr<nsISHistory> h_src;
	result = GetSHistory (getter_AddRefs(h_src));
	if (NS_FAILED(result) || !h_src) return NS_ERROR_FAILURE;

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

	nsCOMPtr<nsISHistory> h_dest;
	result = dest->GetSHistory (getter_AddRefs (h_dest));
	if (!NS_SUCCEEDED (result) || (!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++) 
		{

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

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

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

	return NS_OK;
}


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

	nsCOMPtr<nsISHistory> SessionHistory;
	result = GetSHistory (getter_AddRefs(SessionHistory));
	if (NS_FAILED(result) || ! 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, nsCString &url)
{
	nsresult result;

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

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

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

	result = uri->GetSpec(url);
	if (NS_FAILED(result) || url.IsEmpty()) return NS_ERROR_FAILURE;

	return NS_OK;
}

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

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

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

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

	return NS_OK;
}


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

	mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));

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

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

#if MOZILLA_SNAPSHOT > 11
	nsIURI *uri;
	uri = doc->GetDocumentURL();
#else
	nsCOMPtr<nsIURI> uri;
	doc->GetDocumentURL(getter_AddRefs(uri));
#endif

	return uri->GetSpec(url);
}


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

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

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

#if MOZILLA_SNAPSHOT > 9
	result = mdv->SetForceCharacterSet(nsDependentCString(encoding));
#else
	result = mdv->SetForceCharacterSet(NS_ConvertUTF8toUCS2(encoding).get());
#endif

        return result;
}
