/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/*
 *  bonobo-activation: A library for accessing bonobo-activation-server.
 *
 *  Copyright (C) 2000 Eazel, Inc.
 *  Copyright (C) 2006 Red Hat, Inc.
 *
 *  This 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.
 *
 *  This 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 this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Authors:
 *       Maciej Stachowiak <mjs@eazel.com>
 *       Alexander Larsson <alexl@redhat.com>
 */

#include <config.h>
#include <string.h>
#include "bonobo-activation-mime.h"
#include <bonobo-activation/bonobo-activation-activate.h>
#include <bonobo-activation/bonobo-activation-init.h>

static char *
extract_prefix_add_suffix (const char *string, const char *separator, const char *suffix)
{
        const char *separator_position;
        int prefix_length;
        char *result;

        separator_position = strstr (string, separator);
        prefix_length = separator_position == NULL
                ? strlen (string)
                : separator_position - string;

        result = g_malloc (prefix_length + strlen (suffix) + 1);
        
        strncpy (result, string, prefix_length);
        result[prefix_length] = '\0';

        strcat (result, suffix);

        return result;
}

static char *
get_supertype_from_mime_type (const char *mime_type)
{
	if (mime_type == NULL) {
		return NULL;
	}
        return extract_prefix_add_suffix (mime_type, "/", "/*");
}

static GList *
Bonobo_ServerInfoList_to_ServerInfo_g_list (Bonobo_ServerInfoList *info_list)
{
	GList *retval;
	int i;
	
	retval = NULL;
	if (info_list != NULL && info_list->_length > 0) {
		for (i = 0; i < info_list->_length; i++) {
			retval = g_list_prepend (retval, Bonobo_ServerInfo_duplicate (&info_list->_buffer[i]));
		}
		retval = g_list_reverse (retval);
	}

	return retval;
}

/**
 * bonobo_activation_get_default_component_for_mime_type:
 * @mime_type: a const char * containing a mime type, e.g. "image/png".
 * 
 * Query the MIME database for the default Bonobo component to be activated to 
 * view files of MIME type @mime_type.
 * 
 * Return value: a #Bonobo_ServerInfo * representing the OAF server to be activated
 * to get a reference to the proper component.
 *
 * Since: 2.16.0
 */
Bonobo_ServerInfo *
bonobo_activation_get_default_component_for_mime_type (const char *mime_type)
{
	Bonobo_ServerInfoList *info_list;
	Bonobo_ServerInfo *default_component;
	CORBA_Environment ev;
	char *supertype;
	char *query;
	char *sort[4];

	if (mime_type == NULL) {
		return NULL;
	}

	CORBA_exception_init (&ev);

	supertype = get_supertype_from_mime_type (mime_type);

	/* Find a component that supports either the exact mime type,
           the supertype, or all mime types. */

	query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type, 
			     "', '", supertype,
			     "', '*'])", NULL);

	/* Prefer something that matches the exact type to something
           that matches the supertype */
	sort[0] = g_strconcat ("bonobo:supported_mime_types.has ('", mime_type, "')", NULL);

	/* Prefer something that matches the supertype to something that matches `*' */
	sort[1] = g_strconcat ("bonobo:supported_mime_types.has ('", supertype, "')", NULL);

	sort[2] = g_strdup ("name");
	sort[3] = NULL;

	info_list = bonobo_activation_query (query, sort, &ev);
	
	default_component = NULL;
	if (ev._major == CORBA_NO_EXCEPTION) {
		if (info_list != NULL && info_list->_length > 0) {
			default_component = Bonobo_ServerInfo_duplicate (&info_list->_buffer[0]);
		}
		CORBA_free (info_list);
	}

	g_free (supertype);
	g_free (query);
	g_free (sort[0]);
	g_free (sort[1]);
	g_free (sort[2]);
	g_free (sort[3]);

	CORBA_exception_free (&ev);

	return default_component;
}

/**
 * bonobo_activation_get_all_components_for_mime_type:
 * @mime_type: a const char * containing a mime type, e.g. "image/png".
 * 
 * Return an alphabetically sorted list of #Bonobo_ServerInfo
 * data structures representing all Bonobo components registered
 * to handle files of @mime_type (and supertypes).
 * 
 * Return value: a #GList * where the elements are #Bonobo_ServerInfo *
 * representing components that can handle @mime_type.
 *
 * Since: 2.16.0
 */ 
GList *
bonobo_activation_get_all_components_for_mime_type (const char *mime_type)
{
	Bonobo_ServerInfoList *info_list;
	GList *components_list;
	CORBA_Environment ev;
	char *supertype;
	char *query;
	char *sort[2];

	if (mime_type == NULL) {
		return NULL;
	}

	CORBA_exception_init (&ev);

	/* Find a component that supports either the exact mime type,
           the supertype, or all mime types. */

	/* FIXME bugzilla.eazel.com 1142: should probably check for
           the right interfaces too. Also slightly semantically
           different from nautilus in other tiny ways.
	*/
	supertype = get_supertype_from_mime_type (mime_type);
	query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type, 
			     "', '", supertype,
			     "', '*'])", NULL);
	g_free (supertype);
	
	/* Alphebetize by name, for the sake of consistency */
	sort[0] = g_strdup ("name");
	sort[1] = NULL;

	info_list = bonobo_activation_query (query, sort, &ev);
	
	if (ev._major == CORBA_NO_EXCEPTION) {
		components_list = Bonobo_ServerInfoList_to_ServerInfo_g_list (info_list);
		CORBA_free (info_list);
	} else {
		components_list = NULL;
	}

	g_free (query);
	g_free (sort[0]);

	CORBA_exception_free (&ev);

	return components_list;
}

/* This is code that used to be in gnome-vfs, but that has been moved to bonobo so that
 * gnome-vfs doesn't have to depend on bonobo. We keep the old names to keep binary compatibility,
 * although new users of this should use the bonobo_activation_* calls above instead.
 */

/* There public headers are in gnome-vfs, but you really shouldn't use these functions */
Bonobo_ServerInfo *gnome_vfs_mime_get_default_component       (const char *mime_type);
GList *            gnome_vfs_mime_get_all_components          (const char *mime_type);
void               gnome_vfs_mime_component_list_free         (GList      *list);
GList *            gnome_vfs_mime_remove_component_from_list  (GList      *components,
							       const char *iid,
							       gboolean   *did_remove);
GList *            gnome_vfs_mime_id_list_from_component_list (GList      *components);
gboolean           gnome_vfs_mime_id_in_component_list        (const char *iid,
							       GList      *components);
GList *            gnome_vfs_mime_get_short_list_components   (const char *mime_type);

static void
initialize_bonobo (void)
{
	char *bogus_argv[2] = { "dummy", NULL };
	static gboolean initialized = FALSE;

	if (initialized) {
		return;
	}

	initialized = TRUE;

	if (!bonobo_activation_is_initialized ()) {
		bonobo_activation_init (0, bogus_argv);
	}
	
	return;
}


Bonobo_ServerInfo *
gnome_vfs_mime_get_default_component (const char *mime_type)
{
  initialize_bonobo ();

  return bonobo_activation_get_default_component_for_mime_type (mime_type);
}

GList *
gnome_vfs_mime_get_all_components (const char *mime_type)
{
	initialize_bonobo ();

	return bonobo_activation_get_all_components_for_mime_type (mime_type);
}

GList *
gnome_vfs_mime_get_short_list_components (const char *mime_type)
{
	Bonobo_ServerInfoList *info_list;
	GList *components_list;
	CORBA_Environment ev;
	char *supertype;
	char *query;
	char *sort[4];

	initialize_bonobo ();
	
	if (mime_type == NULL) {
		return NULL;
	}

	CORBA_exception_init (&ev);

	/* Find a component that supports either the exact mime type,
           the supertype, or all mime types. */

	/* FIXME bugzilla.eazel.com 1142: should probably check for
           the right interfaces too. Also slightly semantically
           different from nautilus in other tiny ways.
	*/
	supertype = get_supertype_from_mime_type (mime_type);
	query = g_strconcat ("bonobo:supported_mime_types.has_one (['", mime_type, 
			     "', '", supertype,
			     "', '*'])", NULL);
	g_free (supertype);
	
        /* Prefer something that matches the exact type to something
           that matches the supertype */
	sort[0] = g_strconcat ("bonobo:supported_mime_types.has ('", mime_type, "')", NULL);

	/* Prefer something that matches the supertype to something that matches `*' */
	sort[1] = g_strconcat ("bonobo:supported_mime_types.has ('", supertype, "')", NULL);

	sort[2] = g_strdup ("name");
	sort[3] = NULL;

	info_list = bonobo_activation_query (query, sort, &ev);
	
	if (ev._major == CORBA_NO_EXCEPTION) {
		components_list = Bonobo_ServerInfoList_to_ServerInfo_g_list (info_list);
		CORBA_free (info_list);
	} else {
		components_list = NULL;
	}

	g_free (query);
	g_free (sort[0]);
	g_free (sort[1]);
	g_free (sort[2]);

	CORBA_exception_free (&ev);

	return components_list;
}

static gint 
gnome_vfs_mime_component_matches_id (Bonobo_ServerInfo *component, const char *iid)
{
	return strcmp (component->iid, iid);
}

GList *
gnome_vfs_mime_id_list_from_component_list (GList *components)
{
	GList *list = NULL;
	GList *node;

	for (node = components; node != NULL; node = node->next) {
		list = g_list_prepend 
			(list, g_strdup (((Bonobo_ServerInfo *)node->data)->iid));
	}
	return g_list_reverse (list);
}

gboolean
gnome_vfs_mime_id_in_component_list (const char *iid, GList *components)
{
	return g_list_find_custom
		(components, (gpointer) iid,
		 (GCompareFunc) gnome_vfs_mime_component_matches_id) != NULL;
}

GList *
gnome_vfs_mime_remove_component_from_list (GList *components, 
					   const char *iid,
					   gboolean *did_remove)
{
	GList *matching_node;
	
	matching_node = g_list_find_custom 
		(components, (gpointer)iid,
		 (GCompareFunc) gnome_vfs_mime_component_matches_id);
	if (matching_node != NULL) {
		components = g_list_remove_link (components, matching_node);
		gnome_vfs_mime_component_list_free (matching_node);
	}

	if (did_remove != NULL) {
		*did_remove = matching_node != NULL;
	}
	return components;
}

void
gnome_vfs_mime_component_list_free (GList *list)
{
	g_list_foreach (list, (GFunc) CORBA_free, NULL);
	g_list_free (list);
}



syntax highlighted by Code2HTML, v. 0.9.1