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

/*
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *
 *  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.
 */

#ifndef __KZ_MOZ_UTILS_H__
#define __KZ_MOZ_UTILS_H__

#include <gtk/gtk.h>
#define MOZILLA_INTERNAL_API
#include <nsIComponentManager.h>
#include <nsIServiceManager.h>
#undef MOZILLA_INTERNAL_API
#include <nsIDOMWindow.h>
#include <nsIURI.h>
#include <nsIIOService.h>
#include <nsIInputStream.h>
#include <nsIOutputStream.h>
#include <nsIFileStreams.h>
#include <nsIInputStreamChannel.h>
#include <nsIRequestObserver.h>
#include <nsILoadGroup.h>
#include <nsNetCID.h>
#include <nsCRT.h>
#include <nsCOMPtr.h>
#define MOZILLA_STRICT_API
#include <nsEmbedString.h>
#undef MOZILLA_STRICT_API

	GtkWidget *GetGtkWindowForDOMWindow (nsIDOMWindow* aDOMWindow);

	gboolean  NewURI		    (nsIURI **result,
    					     const char *spec);

/* 
 * The following functions is taken from include/necko/nsNetUtils.h in mozilla
 */

inline nsresult
GetIOService (nsIIOService **ioService)
{
	nsresult rv;

	nsCOMPtr<nsIServiceManager> mgr; 
	NS_GetServiceManager (getter_AddRefs (mgr));
	if (!mgr) return NS_ERROR_FAILURE;

	rv = mgr->GetServiceByContractID (NS_IOSERVICE_CONTRACTID,
					  NS_GET_IID (nsIIOService),
					  (void **)ioService);
	return rv;
}


inline nsresult
NS_NewURI(nsIURI **result, 
          const nsACString &spec, 
          const char *charset = nsnull,
          nsIURI *baseURI = nsnull)
{
    nsresult rv;
    nsCOMPtr<nsIIOService> is;
    rv = GetIOService(getter_AddRefs(is));
    if (is)
        rv = is->NewURI(spec, charset, baseURI, result);
    return rv; 
}

inline nsresult
NS_NewFileURI(nsIURI* *result, 
              nsIFile* spec)
{
    nsresult rv;
    nsCOMPtr<nsIIOService> is;
    rv = GetIOService(getter_AddRefs(is));
    if (is)
        rv = is->NewFileURI(spec, result);
    return rv;
}

inline nsresult
NS_NewInputStreamChannel(nsIChannel      **result,
                         nsIURI           *uri,
                         nsIInputStream   *stream,
                         const nsACString &contentType,
                         const nsACString *contentCharset)
{
    nsresult rv;
    static NS_DEFINE_CID(kInputStreamChannelCID, NS_INPUTSTREAMCHANNEL_CID);
    nsCOMPtr<nsIInputStreamChannel> channel =
        do_CreateInstance(kInputStreamChannelCID, &rv);
    if (NS_SUCCEEDED(rv)) {
        rv |= channel->SetURI(uri);
        rv |= channel->SetContentStream(stream);
        rv |= channel->SetContentType(contentType);
        if (contentCharset && contentCharset->Length()) {
            rv |= channel->SetContentCharset(*contentCharset);
        }
        if (NS_SUCCEEDED(rv))
            NS_ADDREF(*result = channel);
    }
    return rv;
}


inline nsresult
NS_NewChannel(nsIChannel           **result, 
              nsIURI                *uri,
              nsILoadGroup          *loadGroup = nsnull,
              nsIInterfaceRequestor *callbacks = nsnull,
              PRUint32               loadFlags = nsIRequest::LOAD_NORMAL)
{
    nsresult rv;
    nsCOMPtr<nsIIOService> is;
    rv = GetIOService(getter_AddRefs(is));
    if (is) {
        nsIChannel *chan;
        rv = is->NewChannelFromURI(uri, &chan);
        if (NS_SUCCEEDED(rv)) {
            if (loadGroup)
                rv |= chan->SetLoadGroup(loadGroup);
            if (callbacks)
                rv |= chan->SetNotificationCallbacks(callbacks);
            if (loadFlags != nsIRequest::LOAD_NORMAL)
                rv |= chan->SetLoadFlags(loadFlags);
            if (NS_SUCCEEDED(rv))
                *result = chan;
            else
                NS_RELEASE(chan);
        }
    }
    return rv;
}

// Use this function with CAUTION. It creates a stream that blocks when you
// Read() from it and blocking the UI thread is a bad idea. If you don't want
// to implement a full blown asynchronous consumer (via nsIStreamListener) look
// at nsIStreamLoader instead.
inline nsresult
NS_OpenURI(nsIInputStream       **result,
           nsIURI                *uri,
           nsILoadGroup          *loadGroup = nsnull,
           nsIInterfaceRequestor *callbacks = nsnull,
           PRUint32               loadFlags = nsIRequest::LOAD_NORMAL)
{
    nsresult rv;
    nsCOMPtr<nsIChannel> channel;
    rv = NS_NewChannel(getter_AddRefs(channel), uri,
                       loadGroup, callbacks, loadFlags);
    if (NS_SUCCEEDED(rv)) {
        nsIInputStream *stream;
        rv = channel->Open(&stream);
        if (NS_SUCCEEDED(rv))
            *result = stream;
    }
    return rv;
}

inline nsresult
NS_NewLocalFileOutputStream(nsIOutputStream **aResult,
                            nsIFile          *aFile,
                            PRInt32           aIOFlags       = -1,
                            PRInt32           aPerm          = -1,
                            PRInt32           aBehaviorFlags = 0)
{
    nsresult rv;
    static NS_DEFINE_CID(kLocalFileOutputStreamCID, NS_LOCALFILEOUTPUTSTREAM_CID);
    nsCOMPtr<nsIFileOutputStream> out =
        do_CreateInstance(kLocalFileOutputStreamCID, &rv);
    if (NS_SUCCEEDED(rv)) {
        rv = out->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
        if (NS_SUCCEEDED(rv))
            NS_ADDREF(*aResult = out);
    }
    return rv;
}

inline nsresult
NS_NewLoadGroup(nsILoadGroup      **result,
                nsIRequestObserver *obs)
{
    nsresult rv;
    static NS_DEFINE_CID(kLoadGroupCID, NS_LOADGROUP_CID);
    nsCOMPtr<nsILoadGroup> group =
        do_CreateInstance(kLoadGroupCID, &rv);
    if (NS_SUCCEEDED(rv)) {
        rv = group->SetGroupObserver(obs);
        if (NS_SUCCEEDED(rv))
            NS_ADDREF(*result = group);
    }
    return rv;
}

inline void
ToLowerCase (nsAString &aString)
{
	nsEmbedCString cString;

	NS_UTF16ToCString(aString, NS_CSTRING_ENCODING_UTF8, cString);

	gchar *utf8_string = g_utf8_strdown(cString.get(), -1);

	NS_CStringToUTF16(nsEmbedCString(utf8_string),
			  NS_CSTRING_ENCODING_UTF8, aString);

	g_free (utf8_string);
}

inline PRUnichar *
nsEscapeHTML2(const PRUnichar *aSourceBuffer, PRInt32 aSourceBufferLen)
{
  // if the caller didn't calculate the length
  if (aSourceBufferLen == -1) {
    aSourceBufferLen = nsCRT::strlen(aSourceBuffer); // ...then I will
  }

  /* XXX Hardcoded max entity len. */
  PRUnichar *resultBuffer = (PRUnichar *)nsMemory::Alloc(aSourceBufferLen *
                            6 * sizeof(PRUnichar) + sizeof(PRUnichar('\0')));
  PRUnichar *ptr = resultBuffer;

  if (resultBuffer) {
    PRInt32 i;

    for(i = 0; i < aSourceBufferLen; i++) {
      if(aSourceBuffer[i] == '<') {
        *ptr++ = '&';
        *ptr++ = 'l';
        *ptr++ = 't';
        *ptr++ = ';';
      } else if(aSourceBuffer[i] == '>') {
        *ptr++ = '&';
        *ptr++ = 'g';
        *ptr++ = 't';
        *ptr++ = ';';
      } else if(aSourceBuffer[i] == '&') {
        *ptr++ = '&';
        *ptr++ = 'a';
        *ptr++ = 'm';
        *ptr++ = 'p';
        *ptr++ = ';';
      } else if (aSourceBuffer[i] == '"') {
        *ptr++ = '&';
        *ptr++ = 'q';
        *ptr++ = 'u';
        *ptr++ = 'o';
        *ptr++ = 't';
        *ptr++ = ';';
      } else if (aSourceBuffer[i] == '\'') {
        *ptr++ = '&';
        *ptr++ = '#';
        *ptr++ = '3';
        *ptr++ = '9';
        *ptr++ = ';';
      } else {
        *ptr++ = aSourceBuffer[i];
      }
    }
    *ptr = 0;
  }

  return resultBuffer;
}


#endif /* __KZ_MOZ_UTILS_H__ */
