/*
 *  Copyright (C) 2001 Philip Langdale
 *
 *  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.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libgnome/gnome-exec.h>
#include <glib/gi18n.h>
#include <libgnome/gnome-url.h>

#include <gtk/gtkdialog.h>
#include <gtk/gtkmessagedialog.h>

#include <nsString.h>
#include <nsXPIDLString.h>
#include <nsIMailtoUrl.h>
#include <nsCOMPtr.h>
#include <nsIURI.h>
#include <nsIDOMWindow.h>
#include <nsIWindowWatcher.h>
#include <nsIServiceManager.h>

#include "prefs-strings.h"
#include "eel-gconf-extensions.h"

#include "ExternalProtocolService.h"

#define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1"

void OpenLegacyMailer(char *format, nsIMailtoUrl *aURL);

/* Implementation file */
NS_IMPL_ISUPPORTS1(GExternalProtocolService, nsIExternalProtocolService)

GExternalProtocolService::GExternalProtocolService()
{
  NS_INIT_ISUPPORTS();
  /* member initializers and constructor code */
}

GExternalProtocolService::~GExternalProtocolService()
{
  /* destructor code */
}

/* boolean externalProtocolHandlerExists (in string aProtocolScheme); */
NS_IMETHODIMP GExternalProtocolService::
		ExternalProtocolHandlerExists(const char *aProtocolScheme,
					      PRBool *_retval)
{
	NS_ENSURE_ARG_POINTER(_retval);
	if (!aProtocolScheme) return NS_ERROR_NULL_POINTER;

	if (!*aProtocolScheme) return NS_ERROR_INVALID_ARG;

	/* build the config key */
	char *key = g_strconcat ("/desktop/gnome/url-handlers/",
				 aProtocolScheme,
				 "/command", NULL);

	char *tmp = eel_gconf_get_string(key);
	g_free (key);

	*_retval = (tmp != NULL);
	g_free (tmp);

	return NS_OK;
}

/* void loadUrl (in nsIURI aURL); */
NS_IMETHODIMP GExternalProtocolService::LoadUrl(nsIURI *aURL)
{
	nsCAutoString cSpec;
	aURL->GetSpec (cSpec);
	nsCAutoString cScheme;
	aURL->GetScheme (cScheme);

	if (cScheme.Equals("http"))
	{
		nsresult rv;
		nsCOMPtr<nsIWindowWatcher> ww;
		ww = do_GetService(WINDOWWATCHER_CONTRACTID, &rv);
		if (NS_SUCCEEDED(rv))
		{
			nsCOMPtr<nsIDOMWindow> newWin;
			rv = ww->OpenWindow(nsnull, cSpec.get(),
					    nsnull, nsnull, nsnull,
					    getter_AddRefs(newWin));
			if (NS_SUCCEEDED(rv)) return NS_OK;
		}
	}

	nsCOMPtr<nsIMailtoUrl> mailUrl;
	mailUrl = do_QueryInterface (aURL);

	gboolean use_gnome_mailer;
	use_gnome_mailer = eel_gconf_get_boolean (CONF_PROGRAMS_GNOME_MAILER);
	
	if (mailUrl && !use_gnome_mailer)
	{
		char *mailer;
			
		mailer = eel_gconf_get_string (CONF_PROGRAMS_MAILER);
		if (!mailer) return NS_ERROR_FAILURE;

		OpenLegacyMailer (mailer, mailUrl);

		g_free (mailer);
			
		return NS_OK;
	}

	/* build the config key */
	const nsCAutoString key(NS_LITERAL_CSTRING("/desktop/gnome/url-handlers/") +
				cScheme + NS_LITERAL_CSTRING("/command"));

	/* find it */
	char *result = eel_gconf_get_string(key.get());
	if (result)
	{
		gnome_url_show(cSpec.get(), NULL);
		g_free (result);
		return NS_OK;
	}

	/* no luck, so offer the user the option of trying the
	 * default handler -- we don't do this automatically in
	 * case the default handler is erroneously set to galeon */
	result = eel_gconf_get_string("/desktop/gnome/url-handlers/unknown/command");

	/* check there is a default */
	{
		GtkWidget *dialog;
		
		/* throw the error */
		dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0, 
						 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
					         _("Galeon cannot handle this protocol,\n"
				     	         "and no GNOME default handler is set"));
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (dialog);
		
		/* don't let mozilla try blindly */
		return NS_ERROR_FAILURE;
	}
	g_free (result);

	/* offer the choice */
	GtkWidget *dialog = gtk_message_dialog_new (NULL, (GtkDialogFlags)0, 
						    GTK_MESSAGE_QUESTION,
						    GTK_BUTTONS_YES_NO,
						    _("The protocol specified "
						     "is not recognised.\n\n"
						     "Would you like to try "
						     "the GNOME default?"));
	
	int ret = gtk_dialog_run (GTK_DIALOG(dialog));
	gtk_widget_destroy (dialog);

	if (ret == 0)
	{
		gnome_url_show(cSpec.get(), NULL);		
		return NS_OK;
	}
	else
	{
		return NS_ERROR_FAILURE;
	}

	return NS_OK;
}

#if MOZILLA_SNAPSHOT > 12
NS_IMETHODIMP GExternalProtocolService::IsExposedProtocol(const char *aProtocolScheme, PRBool *_retval)
{
	*_retval = PR_TRUE;

	return NS_OK;
}
#endif

/*
 * Open a legacy mailer according to preferences command
 *
 * Options:
 *
 * %t To
 * %c Cc
 * %b Bcc
 * %k Organization
 * %w News host
 * %n News group
 * %p Priority
 * %a Attachment
 * %e Reference
 * %h Html
 * %y Body
 * %s Subject
 * %r Reply
 * %o Follow up
 * [ ] ignore all content if the part is null
 */
void OpenLegacyMailer(char *format, nsIMailtoUrl *aURL)
{
	gchar *ToPart, *CcPart, *BccPart, *FromPart, 
		*FollowUpToPart, *OrganizationPart, 
		*ReplyToPart, *SubjectPart, *BodyPart, 
		*HtmlPart, *ReferencePart, *AttachmentPart, 
		*PriorityPart, *NewsgroupPart, *NewsHostPart;
	/* FIXME not used */
	gboolean forcePlainText;
	
	int length, i, j, subpos = -1;
	char *copy, *command;

	aURL->GetMessageContents (&ToPart, 
				  &CcPart, 
				  &BccPart, 
				  &FromPart, 
				  &FollowUpToPart, 
				  &OrganizationPart, 
				  &ReplyToPart, 
				  &SubjectPart, 
				  &BodyPart, 
				  &HtmlPart, 
				  &ReferencePart, 
				  &AttachmentPart, 
				  &PriorityPart, 
				  &NewsgroupPart, 
				  &NewsHostPart, 
				  &forcePlainText);

	/* get the format string */
        length = strlen (format);
	
	int mem = length;
	mem += ToPart != NULL ? strlen (ToPart) : 0;
	mem += CcPart != NULL ? strlen (CcPart) : 0;
	mem += FromPart != NULL ? strlen (FromPart) : 0;
	mem += FollowUpToPart != NULL ? strlen (FollowUpToPart) : 0;
	mem += OrganizationPart != NULL ? strlen (OrganizationPart) : 0;
	mem += ReplyToPart != NULL ? strlen (ReplyToPart) : 0;
	mem += SubjectPart != NULL ? strlen (SubjectPart) : 0;
	mem += BodyPart != NULL ? strlen (BodyPart) : 0;
	mem += HtmlPart != NULL ? strlen (HtmlPart) : 0;
	mem += ReferencePart != NULL ? strlen (ReferencePart) : 0;
	mem += AttachmentPart != NULL ? strlen (AttachmentPart) : 0;
	mem += PriorityPart != NULL ? strlen (PriorityPart) : 0;
	mem += NewsgroupPart != NULL ? strlen (NewsgroupPart) : 0;
	mem += NewsHostPart != NULL ? strlen (NewsHostPart) : 0;
	mem += BccPart != NULL ? strlen (BccPart) : 0;
	
	/* make a target string of maximal size */
        command = (char *) g_malloc (mem);
                                  
        /* parse the format string doing substitutions */
        for (i = 0, j = 0; i < length; i++)
        {
		if (format[i] == '[')
		{
			subpos = j;
		}
		else if (format[i] == ']')
		{
			subpos = -1;
		}
		else if (format[i] == '%' && (i == 0 || format[i - 1] != '\\'))
                {
                        /* check the format character */
                        switch (format[++i])
                        {
                        case 'k':
                                copy = OrganizationPart;
                                break;
                        case 'w':
                                copy = NewsHostPart;
                                break;
                        case 'n':
                                copy = NewsgroupPart;
                                break;
                        case 'p':
                                copy = PriorityPart;
                                break;
                        case 'a':
                                copy = AttachmentPart;
                                break;
                        case 'e':
                                copy = ReferencePart;
                                break;
                        case 'h':
                                copy = HtmlPart;
                                break;
                        case 'y':
                                copy = BodyPart;
                                break;
                        case 's':
                                copy = SubjectPart;
                                break;
                        case 'r':
                                copy = ReplyToPart;
                                break;
                        case 'o':
                                copy = FollowUpToPart;
                                break;
                        case 'f':
                                copy = FromPart;
                                break;
                        case 't':
                                copy = ToPart;
                                break;
                        case 'c':
                                copy = CcPart;
                                break;
                        case 'b':
                                copy = BccPart;
                                break;
                        default:
                                copy = NULL;
                                break;
                        }
                        
                        /* copy substitute string */
                        if (copy != NULL && strlen (copy) > 0)
                        {
				strcpy (command + j, copy);
                                j += strlen (copy);
                        }
			else
			{
				if (subpos>0)
				{
					j = subpos - 1;
					while (i<length &&
					       format[i] != ']')
					{
						i++;
					}
					subpos = -1;
				}
			}
                }
                else
                {
                        command[j++] = format[i];
                }
        }
        command[j] = '\0';

        /* execute the command */
        gnome_execute_shell (NULL, command);
        
        /* free allocated strings */
	g_free (command);
        nsMemory::Free (ToPart);
	nsMemory::Free (CcPart); 
	nsMemory::Free (BccPart);
	nsMemory::Free (FromPart);
	nsMemory::Free (FollowUpToPart);
	nsMemory::Free (OrganizationPart);
	nsMemory::Free (ReplyToPart);
	nsMemory::Free (SubjectPart);
	nsMemory::Free (BodyPart);
	nsMemory::Free (HtmlPart);
	nsMemory::Free (ReferencePart);
	nsMemory::Free (AttachmentPart);
	nsMemory::Free (PriorityPart);
	nsMemory::Free (NewsgroupPart);
	nsMemory::Free (NewsHostPart);
}
