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

//  This file is based on nsAboutProtocolHandler.cpp in Mozilla.
//  The Initial Developer of the Original Code is 
//  Netscape Communications Corporation.
//  Portions created by the Initial Developer are Copyright (C) 1998
//  the Initial Developer. All Rights Reserved.
//
//  Contributor(s):
//   Pierre Phaneuf <pp@ludusdesign.com>


#include <nsIURI.h>
#include <nsIIOService.h>
#include <nsCRT.h>
#include <nsIStorageStream.h>
#include <nsIOutputStream.h>
#define MOZILLA_STRICT_API
#include <nsEmbedString.h>
#undef MOZILLA_STRICT_API
#include <nsNetCID.h>
#include <nsILocalFile.h>
#include <nsMemory.h>

#include <glib.h>

#include "kz-mozhistorysearch.h"
#include "kz-mozutils.h"
#include "MozillaPrivate.h"
#include "config.h"
#include "kz-search.h"
#include "kazehakase.h"

static NS_DEFINE_CID(kSimpleURICID,     NS_SIMPLEURI_CID);

////////////////////////////////////////////////////////////////////////////////

KzMozHistorySearchProtocolHandler::KzMozHistorySearchProtocolHandler()
{
}

nsresult
KzMozHistorySearchProtocolHandler::Init()
{
	return NS_OK;
}

KzMozHistorySearchProtocolHandler::~KzMozHistorySearchProtocolHandler()
{
}

NS_IMPL_ISUPPORTS1(KzMozHistorySearchProtocolHandler, nsIProtocolHandler)


NS_METHOD
KzMozHistorySearchProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
	if (aOuter)
		return NS_ERROR_NO_AGGREGATION;

	KzMozHistorySearchProtocolHandler* ph = new KzMozHistorySearchProtocolHandler();
	if (ph == nsnull)
		return NS_ERROR_OUT_OF_MEMORY;
	NS_ADDREF(ph);
	nsresult rv = ph->Init();
	if (NS_SUCCEEDED(rv)) {
		rv = ph->QueryInterface(aIID, aResult);
	}
	NS_RELEASE(ph);
	return rv;
}

////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:

NS_IMETHODIMP
KzMozHistorySearchProtocolHandler::GetScheme(nsACString &result)
{
	result = "history-search";
	return NS_OK;
}

NS_IMETHODIMP
KzMozHistorySearchProtocolHandler::GetDefaultPort(PRInt32 *result)
{
	*result = -1;        // no port for about: URLs
	return NS_OK;
}

NS_IMETHODIMP
KzMozHistorySearchProtocolHandler::GetProtocolFlags(PRUint32 *result)
{
	*result = URI_NORELATIVE | URI_NOAUTH;
	return NS_OK;
}

NS_IMETHODIMP
KzMozHistorySearchProtocolHandler::NewURI(const nsACString &aSpec,
	                                  const char *aCharset, // ignore charset info
					  nsIURI *aBaseURI,
					  nsIURI **result)
{
	nsresult rv;

	nsIURI* url;
	
	nsCOMPtr<nsIComponentManager> cm;
	NS_GetComponentManager(getter_AddRefs(cm));

	if (!cm) return NS_ERROR_FAILURE;

	rv =cm->CreateInstance(kSimpleURICID, nsnull, NS_GET_IID(nsIURI),
	    		       (void**)&url);
	if (NS_FAILED(rv)) return rv;
	
	rv = url->SetSpec(aSpec);
	if (NS_FAILED(rv))
	{
		NS_RELEASE(url);
		return rv;
	}
	
	*result = url;
	return rv;
}


static NS_IMETHODIMP
OpenStylesheet (nsIURI* uri, nsIChannel* *result)
{
	nsresult rv;
	nsEmbedCString text, cssName;
	PRUint32 length;
	rv = uri->GetPath(text);

	length = text.Length();

	gchar *filename = g_strconcat(KZ_DATADIR G_DIR_SEPARATOR_S, text.get() + 5, NULL);

	nsCOMPtr<nsILocalFile> cssFile;
	rv = NS_NewNativeLocalFile(nsEmbedCString(filename), PR_TRUE,
		                   getter_AddRefs(cssFile));
	g_free (filename);

	nsCOMPtr<nsIURI> cssURI;
	rv = NS_NewFileURI(getter_AddRefs(cssURI), cssFile);
	if (NS_FAILED(rv)) return rv;

	nsCOMPtr<nsIInputStream> iStream;
	rv = NS_OpenURI(getter_AddRefs(iStream), cssURI);
	if (NS_FAILED(rv)) return rv;

	rv = NS_NewInputStreamChannel(result, uri,
				      iStream, nsEmbedCString("text/css"),
				      nsnull);
	return rv;
}


static NS_IMETHODIMP
OpenImage (nsIURI* uri, nsIChannel* *result)
{
	nsresult rv;
	nsEmbedCString text;
	PRUint32 length;
	rv = uri->GetPath(text);

	length = text.Length();

	gchar *filename = g_strndup(text.get() + 7, length - 7);

	nsCOMPtr<nsILocalFile> cssFile;
	rv = NS_NewNativeLocalFile(nsEmbedCString(filename), PR_TRUE,
		                   getter_AddRefs(cssFile));
	g_free (filename);

	nsCOMPtr<nsIURI> cssURI;
	rv = NS_NewFileURI(getter_AddRefs(cssURI), cssFile);
	if (NS_FAILED(rv)) return rv;

	nsCOMPtr<nsIInputStream> iStream;
	rv = NS_OpenURI(getter_AddRefs(iStream), cssURI);
	if (NS_FAILED(rv)) return rv;

	rv = NS_NewInputStreamChannel(result, uri,
				      iStream, nsEmbedCString("image/png"),
				      nsnull);
	return rv;
}


NS_IMETHODIMP
KzMozHistorySearchProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
{
	nsresult rv;
	nsEmbedCString text;
	rv = uri->GetPath(text);
	if (NS_FAILED(rv)) return rv;
	
	if (!g_ascii_strncasecmp(text.get(), "?css=", 5))
	{
		rv = OpenStylesheet(uri, result);
		return rv;
	}

	if (!g_ascii_strncasecmp(text.get(), "?image=", 7))
	{
		rv = OpenImage(uri, result);
		return rv;
	}

	char *unescaped = nsCRT::strdup(text.get());
	unescaped = (char*)MozillaPrivate::Unescape(unescaped);

	nsCOMPtr<nsIStorageStream> sStream;
	nsCOMPtr<nsIOutputStream> stream;

	rv = NS_NewStorageStream(16384, (PRUint32)-1, getter_AddRefs(sStream));
	if (NS_FAILED(rv)) return rv;

	rv = sStream->GetOutputStream(0, getter_AddRefs(stream));
	if (NS_FAILED(rv)) return rv;
	
	/* render the complete portal */
	gchar *html = NULL;
	if (KZ_GET_SEARCH)
		html = kz_search_get_search_result_html(KZ_GET_SEARCH, unescaped);

	nsMemory::Free(unescaped);
	if (html)
	{
		PRUint32 bytesWritten;
        	stream->Write (html, strlen(html), &bytesWritten);
		g_free(html);
	}
	nsCOMPtr<nsIInputStream> iStream;
	rv = sStream->NewInputStream(0, getter_AddRefs(iStream));
	if (NS_FAILED(rv)) return rv;

	rv = NS_NewInputStreamChannel(result, uri,
				      iStream, nsEmbedCString("text/html"),
				      nsnull);
	if (NS_FAILED(rv)) return rv;

	return rv;
}

NS_IMETHODIMP 
KzMozHistorySearchProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
{
	// don't override anything.  
	*_retval = PR_FALSE;
	return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
