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

/* nautilus-xds-dnd.c - XDS drop handling for Nautilus.

   Copyright (C) 2005 Free Software Foundation, Inc.

   The Gnome Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The Gnome Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Authors: Christian Neumair <chris@gnome-de.org>
*/

#include "nautilus-xds-dnd.h"

#include "nautilus-file.h"

#include <string.h>
#include <glib.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>

#define MAX_XDS_ATOM_VAL_LEN 4096

#define XDS_ATOM  gdk_atom_intern  ("XdndDirectSave0", FALSE)
#define TEXT_ATOM gdk_atom_intern  ("text/plain", FALSE)
#define OCTET_ATOM gdk_atom_intern ("application/octet-stream", FALSE)

static char *
get_xds_atom_value (GdkDragContext *context)
{
	char *ret;

	g_return_val_if_fail (context != NULL, NULL);
	g_return_val_if_fail (context->source_window != NULL, NULL);

	gdk_property_get (context->source_window,
			  XDS_ATOM, TEXT_ATOM,
			  0, MAX_XDS_ATOM_VAL_LEN,
			  FALSE, NULL, NULL, NULL,
			  (unsigned char **) &ret);

	return ret;
}

static void
set_xds_atom_value (GdkDragContext *context,
		    char *value)
{
	g_return_if_fail (context != NULL);
	g_return_if_fail (value != NULL);

	gdk_property_change (context->source_window,
			     XDS_ATOM, TEXT_ATOM,
			     8, GDK_PROP_MODE_REPLACE,
			     value, strlen (value));
}

static gboolean
context_offers_target (GdkDragContext *context,
		       GdkAtom target)
{
	return (g_list_find (context->targets, target) != NULL);
}

gboolean
nautilus_xds_dnd_is_valid_xds_context (GdkDragContext *context)
{
	char *tmp;
	gboolean ret;

	g_return_val_if_fail (context != NULL, FALSE);

	tmp = NULL;
	if (context_offers_target (context, XDS_ATOM)) {
		tmp = get_xds_atom_value (context);
	}

	ret = (tmp != NULL);
	g_free (tmp);

	return ret;
}

char *
nautilus_xds_dnd_handle_drop_stage_1 (NautilusFile *target_dir,
				      GdkDragContext *context)
{
	GnomeVFSURI *target_vfs_uri, *target_dir_vfs_uri;
	char *target_dir_uri, *target_uri, *xds_filename;

	g_return_val_if_fail (target_dir != NULL, NULL);

	if (!nautilus_file_can_write (target_dir)) {
		return NULL;
	}

	target_dir_uri = nautilus_file_get_drop_target_uri (target_dir);
	target_dir_vfs_uri = gnome_vfs_uri_new (target_dir_uri);
	g_return_val_if_fail (target_dir_vfs_uri != NULL, NULL);

	xds_filename = get_xds_atom_value (context);
	g_return_val_if_fail (xds_filename != NULL, NULL);

	target_vfs_uri = gnome_vfs_uri_append_file_name (target_dir_vfs_uri, xds_filename);
	target_uri = gnome_vfs_uri_to_string (target_vfs_uri, GNOME_VFS_URI_HIDE_NONE);
	g_return_val_if_fail (target_uri != NULL, NULL);

	set_xds_atom_value (context, target_uri);

	gnome_vfs_uri_unref (target_vfs_uri);
	gnome_vfs_uri_unref (target_dir_vfs_uri);
	g_free (target_dir_uri);
	g_free (xds_filename);

	return target_uri;
}

XDSDropStage2Result
nautilus_xds_dnd_handle_drop_stage_2 (GtkWidget *widget,
				      GdkDragContext *context,
				      GtkSelectionData *data,
				      guint32 time)
{
	g_return_val_if_fail (nautilus_xds_dnd_is_valid_xds_context (context), FALSE);
	g_return_val_if_fail (data != NULL, FALSE);

	if (strcmp (data->data, "S") == 0) { /* success */
		return XDS_DROP_STAGE_2_RESULT_SUCCESS;
	} else if (strcmp (data->data, "F") == 0) { /* failure */
		if (context_offers_target (context, OCTET_ATOM)) {
			/* try to retreive data as octet stream */
			gtk_drag_get_data (widget, context,
					   OCTET_ATOM, time);

			return XDS_DROP_STAGE_2_RESULT_FAILURE_BUT_OCTET;
		} else {
			gdk_property_change (context->source_window,
					     XDS_ATOM, TEXT_ATOM,
					     8, GDK_PROP_MODE_REPLACE, NULL, 0);

			return XDS_DROP_STAGE_2_RESULT_FAILURE;
		}
	} else if (strcmp (data->data, "E") == 0) { /* error */
		return XDS_DROP_STAGE_2_RESULT_ERROR;
	} else {
		g_warning ("unexpected XDS response in %s: %s", __FUNCTION__, data->data);

		return XDS_DROP_STAGE_2_RESULT_ERROR;
	}
}
