/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  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 "ProgressListener.h"
#include "mozilla-embed-persist.h"
#include "mozilla-embed.h"
#include "GaleonWrapper.h"
#include "gul-general.h"
#include "HeaderSniffer.h"
#include "galeon-debug.h"

#include <stddef.h>
#include <nsIURIChecker.h>
#include <nsString.h>
#include <nsIHistoryEntry.h>
#include <nsISHEntry.h>
#include <nsNetUtil.h>
#include <nsISupportsPrimitives.h>
#include "nsIDOMDocument.h"
#include "nsIDOMNSDocument.h"

struct MozillaEmbedPersistPrivate
{
	gpointer dummy;
};

static GObjectClass *parent_class = NULL;

#define MOZILLA_EMBED_PERSIST_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
					MOZILLA_EMBED_PERSIST_TYPE, MozillaEmbedPersistPrivate))

static gresult 
impl_save (GaleonEmbedPersist *persist)
{
	nsresult rv;
	char *filename;
	char *uri;
	long max_size;
	GaleonEmbed *embed;
	EmbedPersistFlags flags;

	/* FIXME implement max size */

	g_object_get (persist,
		      "source", &uri,        
		      "dest", &filename,
		      "flags", &flags,
		      "embed", &embed,
		      "max_size", &max_size,
		      NULL);

	g_return_val_if_fail (uri || embed, G_FAILED);

	GaleonWrapper *wrapper = NULL;
	if (embed)
	{
		/* Don't bother holding the ref to the embed, its not about
		 * to go away */
		g_object_unref (embed);

		wrapper = (GaleonWrapper *) mozilla_embed_get_galeon_wrapper (MOZILLA_EMBED(embed));
		NS_ENSURE_TRUE (wrapper, G_FAILED);
	}

	/* Get the uri to save from */
	nsCOMPtr<nsIURI> inURI;
	nsCAutoString sURI;
	if (uri)
	{
		sURI.Assign (uri);
	}
	else if (flags & EMBED_PERSIST_MAINDOC)
	{
		rv = wrapper->GetMainDocumentUrl (sURI);
		NS_ENSURE_SUCCESS (rv, G_FAILED);
	}
	else
	{
		rv = wrapper->GetDocumentUrl (sURI);
		NS_ENSURE_SUCCESS (rv, G_FAILED);
	}
      	NS_NewURI(getter_AddRefs(inURI), sURI);
	if (!inURI) return G_FAILED;

	/* If the URI wasn't specified, we are using the embed, so
	 * get the post data, DOM document and pageDescriptor */
	nsCOMPtr<nsIInputStream> postData;
	nsCOMPtr<nsIDOMDocument> DOMDocument;
	nsCOMPtr<nsISupports> pageDescriptor;
	if (!uri)
	{
		/* Post data */
		nsCOMPtr<nsISHistory> sessionHistory;
		nsCOMPtr<nsIHistoryEntry> entry;
		nsCOMPtr<nsIWebNavigation> webNav;
		PRInt32 sindex;

		webNav = do_QueryInterface(wrapper->mWebBrowser);
		webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
		sessionHistory->GetIndex(&sindex);
		sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry));
		nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(entry));
		if (shEntry)
		{
			shEntry->GetPostData(getter_AddRefs(postData));
		}

		/* get the DOMDocument */
		if (flags & EMBED_PERSIST_MAINDOC)
		{
                	wrapper->GetMainDOMDocument (getter_AddRefs(DOMDocument));
		}
        	else
		{
                	wrapper->GetDOMDocument (getter_AddRefs(DOMDocument));
		}
        	NS_ENSURE_TRUE (DOMDocument, G_FAILED);

		/* and get the page descriptor */
	        wrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
		/* Its not the end of the world if we don't get
		 * a pageDescriptor, mozilla doesn't even appear to use
		 * it */
	}

	/* Only use the save document code if it an appropriate mime type,
	 * we turn off the document save code, by just setting the
	 * DOMDocument to null */
	if (DOMDocument)
	{
		nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(DOMDocument);
		nsAutoString contentType;
		if (doc)
		{
			doc->GetContentType (contentType);
		}

		if (contentType != NS_LITERAL_STRING ("text/html") &&
		    contentType != NS_LITERAL_STRING ("text/xml")  &&
		    contentType != NS_LITERAL_STRING ("application/xhtml+xml"))
		{
			DOMDocument = nsnull;
		}
	}

	if (filename == NULL)
	{
		/* Create an header sniffer and do the save */
		HeaderSniffer* sniffer = new HeaderSniffer (persist, inURI,
							    DOMDocument, 
							    postData,
							    pageDescriptor);

		nsCOMPtr<nsIURIChecker> uri_checker = do_CreateInstance
			(NS_URICHECKER_CONTRACT_ID);

		rv = uri_checker->Init (inURI);
		if (NS_FAILED (rv)) return G_FAILED;

		PRInt32 checker_flags = 0;
		if (flags & EMBED_PERSIST_BYPASSCACHE)
		{
			checker_flags |= nsIRequest::LOAD_BYPASS_CACHE;
		}
		else
		{
			checker_flags |= nsIRequest::LOAD_FROM_CACHE;
		}
		
		uri_checker->SetLoadFlags (checker_flags);

		/* Start the checker, the sniffer will inspect
		 * the headers when it finishes */
		uri_checker->AsyncCheck (sniffer, nsnull);
 	}
	else
	{
		/* Filename to save to */
		nsCOMPtr<nsILocalFile> destFile;
		NS_NewNativeLocalFile (nsDependentCString(filename),
				       PR_TRUE, getter_AddRefs(destFile));
	        NS_ENSURE_TRUE (destFile, G_FAILED);

		rv =  InitiateMozillaDownload (inURI, destFile,
					       persist, DOMDocument,
					       pageDescriptor, postData,
					       PR_TRUE, inURI);
		if (NS_FAILED (rv)) return G_FAILED;
	}

	g_free (uri);
	g_free (filename);

	return G_OK;
}

static void
mozilla_embed_persist_init (MozillaEmbedPersist *persist)
{
	persist->priv = MOZILLA_EMBED_PERSIST_GET_PRIVATE (persist);
}

static void
mozilla_embed_persist_finalize (GObject *object)
{
	G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
mozilla_embed_persist_class_init (MozillaEmbedPersistClass *klass)
{
	GObjectClass *object_class;
	GaleonEmbedPersistClass *persist_class;
	
	parent_class = (GObjectClass *) g_type_class_peek_parent (klass);

	persist_class = GALEON_EMBED_PERSIST_CLASS (klass);
	object_class  = G_OBJECT_CLASS (klass);

	object_class->finalize = mozilla_embed_persist_finalize;
	persist_class->save = impl_save;

	g_type_class_add_private (object_class, sizeof (MozillaEmbedPersistPrivate));
}

G_DEFINE_TYPE (MozillaEmbedPersist, mozilla_embed_persist, GALEON_EMBED_PERSIST_TYPE);
