#include <gtk/gtk.h>
#include "guiutils.h"
#include "edv_mime_type.h"
#include "endeavour2.h"
#include "edv_open_to_menu.h"
#include "edv_open_cb.h"


static void EDVOpenToMenuDataDestroyCB(gpointer data);

GtkWidget *EDVOpenToMenuNewFromMIMEType(
	edv_core_struct *core,
	edv_mime_type_struct *m,
	GList *(*paths_list_get_cb)(gpointer),
	gpointer paths_list_get_data,
	void (*goto_directory_cb)(gpointer, const gchar *),
	gpointer goto_directory_data,
	GtkWidget *toplevel,
	const gboolean verbose
);


#define EDV_OPEN_DATA_KEY	"EDV_OPEN_DATA"

#define ATOI(s)		(((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)		(((s) != NULL) ? atol(s) : 0)
#define ATOF(s)		(((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)	(((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)	(((a) > (b)) ? (a) : (b))
#define MIN(a,b)	(((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)	(MIN(MAX((a),(l)),(h)))
#define STRLEN(s)	(((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)	(((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	Data destroy callback.
 */
static void EDVOpenToMenuDataDestroyCB(gpointer data)
{
	EDVOpenCBDataDelete(EDV_OPEN_CB_DATA(data));
}


/*
 *	Creates a new Open To menu from the specified MIME Type.
 *
 *	The m specifies the MIME Type who's command names are to be
 *	added to the new menu. If m is NULL then an new empty menu
 *	will be returned.
 *
 *	The paths_list_get_cb specifies the callback function to
 *	obtain a list of paths. This function needs to return a GList
 *	which member data pointing to a dynamically allocated string
 *	describing the full path to the object.
 *
 *	Returns the new Open To menu.
 */
GtkWidget *EDVOpenToMenuNewFromMIMEType(
	edv_core_struct *core,
	edv_mime_type_struct *m,
	GList *(*paths_list_get_cb)(gpointer),
	gpointer paths_list_get_data,
        void (*goto_directory_cb)(gpointer, const gchar *),
        gpointer goto_directory_data,                    
	GtkWidget *toplevel,
	const gboolean verbose
)
{
	const gchar *command_name;
	GtkAccelGroup *accelgrp = NULL;
	GtkWidget *w, *menu = GUIMenuCreate();
	edv_open_cb_data_struct *d;


#define DO_ADD_MENU_ITEM_LABEL(_name_,_icon_data_,_data_) { \
 w = GUIMenuItemCreate(				\
  menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,	\
  (_icon_data_), (_name_),			\
  0, 0,						\
  NULL,						\
  (_data_), EDVOpenCB				\
 );						\
 if((_data_) != NULL)				\
  gtk_object_set_data_full(			\
   GTK_OBJECT(w), EDV_OPEN_DATA_KEY,		\
   (_data_), EDVOpenToMenuDataDestroyCB		\
  );						\
}

#define DO_ADD_MENU_SEP {			\
 w = GUIMenuItemCreate(				\
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL,	\
  NULL, NULL, 0, 0, NULL,			\
  NULL, NULL					\
 );						\
}

	/* No MIME Type specified? */
	if(m == NULL)
	{
	    if(paths_list_get_cb != NULL)
	    {
		/* Create a menu item based on the last selected
		 * object's type and permissions
		 */
		GList *paths_list = paths_list_get_cb(
		    paths_list_get_data
		);
		if(paths_list != NULL)
		{
		    struct stat stat_buf;
		    const gchar *path;
		    GList *glist = g_list_last(paths_list);

		    if(glist == NULL)
			glist = paths_list;

		    command_name = "Unknown";

		    path = (const gchar *)glist->data;
		    if((path != NULL) ?
			!stat((const char *)path, &stat_buf) : FALSE
		    )
		    {
			edv_object_struct *obj = EDVObjectNew();
			if(obj != NULL)
			{
			    EDVObjectSetPath(obj, path);
			    EDVObjectSetStat(obj, &stat_buf);

			    /* File? */
			    if(EDV_OBJECT_IS_FILE(obj))
			    {
				const edv_permission_flags p = obj->permissions;
				if((p & EDV_PERMISSION_UEXECUTE) ||
				   (p & EDV_PERMISSION_GEXECUTE) ||
				   (p & EDV_PERMISSION_AEXECUTE)
				)
				    command_name = "Execute";
				else
				    command_name = "View";
			    }
			    /* Directory? */
			    else if(EDV_OBJECT_IS_DIRECTORY(obj))
			    {
				command_name = "Go To";
			    }

			    EDVObjectDelete(obj);
			}
		    }
		    g_list_foreach(paths_list, (GFunc)g_free, NULL);
		    g_list_free(paths_list);

                    d = EDVOpenCBDataNew();
                    d->core = core;
                    d->paths_list_get_cb = paths_list_get_cb;
                    d->paths_list_get_data = paths_list_get_data;
		    d->goto_directory_cb = goto_directory_cb;
		    d->goto_directory_data = goto_directory_data;
                    d->command_name = STRDUP(command_name);
                    d->toplevel = toplevel;
                    d->verbose = TRUE;
		    DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		}
		else
		{
		    w = GUIMenuItemCreate(
			menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,
			NULL, "(None)",
			0, 0,
			NULL,
			NULL, NULL
		    );
		    gtk_widget_set_sensitive(w, FALSE);
		}
	    }
	    else
	    {
		w = GUIMenuItemCreate(
		    menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,
		    NULL, "(None)",
		    0, 0,
		    NULL,
		    NULL, NULL
		);
		gtk_widget_set_sensitive(w, FALSE);
	    }
	    return(menu);
	}

	/* Create the menu items by the MIME Type's class */
	switch(m->mt_class)
	{
	  case EDV_MIME_TYPE_CLASS_SYSTEM:
	    if(paths_list_get_cb != NULL)
	    {
		/* Create a menu item based on the last selected
		 * object's type and permissions
		 */
		GList *paths_list = paths_list_get_cb(
		    paths_list_get_data
		);
		if(paths_list != NULL)
		{
		    struct stat stat_buf;
		    const gchar *path;
		    GList *glist = g_list_last(paths_list);

		    if(glist == NULL)
			glist = paths_list;

		    command_name = "Unknown";

		    path = (const gchar *)glist->data;
		    if((path != NULL) ?
			!stat((const char *)path, &stat_buf) : FALSE
		    )
		    {
			edv_object_struct *obj = EDVObjectNew();
			if(obj != NULL)
			{
			    EDVObjectSetPath(obj, path);
			    EDVObjectSetStat(obj, &stat_buf);

			    /* File? */
			    if(EDV_OBJECT_IS_FILE(obj))
			    {
				const edv_permission_flags p = obj->permissions;
				if((p & EDV_PERMISSION_UEXECUTE) ||
				   (p & EDV_PERMISSION_GEXECUTE) ||
				   (p & EDV_PERMISSION_AEXECUTE)
				)
				    command_name = "Execute";
				else
				    command_name = "View";
			    }
			    /* Directory? */
			    else if(EDV_OBJECT_IS_DIRECTORY(obj))
			    {
				command_name = "Go To";
			    }

			    EDVObjectDelete(obj);
			}
		    }
		    g_list_foreach(paths_list, (GFunc)g_free, NULL);
		    g_list_free(paths_list);

                    d = EDVOpenCBDataNew();
                    d->core = core;
                    d->paths_list_get_cb = paths_list_get_cb;
                    d->paths_list_get_data = paths_list_get_data;
		    d->goto_directory_cb = goto_directory_cb;
		    d->goto_directory_data = goto_directory_data;
                    d->command_name = STRDUP(command_name);
                    d->toplevel = toplevel;
                    d->verbose = TRUE;
		    DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		}
		else
		{
		    w = GUIMenuItemCreate(
			menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,
			NULL, "(None)",
			0, 0,
			NULL,
			NULL, NULL
		    );
		    gtk_widget_set_sensitive(w, FALSE);
		}
	    }
	    else
	    {
		w = GUIMenuItemCreate(
		    menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,
		    NULL, "(None)",
		    0, 0,
		    NULL,
		    NULL, NULL
		);
		gtk_widget_set_sensitive(w, FALSE);
	    }
	    break;

	  case EDV_MIME_TYPE_CLASS_FORMAT:
	  case EDV_MIME_TYPE_CLASS_PROGRAM:
	  case EDV_MIME_TYPE_CLASS_UNIQUE:
	    switch(m->handler)
	    {
	      case EDV_MIME_TYPE_HANDLER_COMMAND:
		if(m->commands_list != NULL)
		{
		    const gchar *command_name;
		    GList *glist;
		    edv_mime_type_command_struct *cmd;

		    for(glist = m->commands_list;
			glist != NULL;
			glist = g_list_next(glist)
		    )
		    {
			cmd = EDV_MIME_TYPE_COMMAND(glist->data);
			if(cmd == NULL)
			    continue;

			command_name = cmd->name;
			d = EDVOpenCBDataNew();
			d->core = core;
			d->paths_list_get_cb = paths_list_get_cb;
			d->paths_list_get_data = paths_list_get_data;
			d->goto_directory_cb = goto_directory_cb;
			d->goto_directory_data = goto_directory_data;
			d->command_name = STRDUP(command_name);
			d->toplevel = toplevel;
			d->verbose = TRUE;
			DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		    }
		}
		else
		{
		    w = GUIMenuItemCreate(
			menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,
			NULL, "(None)",
			0, 0,
			NULL,
			NULL, NULL
		    );
		    gtk_widget_set_sensitive(w, FALSE);
		}
		break;

	      case EDV_MIME_TYPE_HANDLER_EDV_ARCHIVER:
		command_name = "Archiver";
                d = EDVOpenCBDataNew();
                d->core = core;
                d->paths_list_get_cb = paths_list_get_cb;
                d->paths_list_get_data = paths_list_get_data;
		d->goto_directory_cb = goto_directory_cb;
		d->goto_directory_data = goto_directory_data;
                d->command_name = STRDUP(command_name);
                d->toplevel = toplevel;
                d->verbose = TRUE;
                DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		break;

	      case EDV_MIME_TYPE_HANDLER_EDV_IMAGE_BROWSER:
		command_name = "Image Browser";
                d = EDVOpenCBDataNew();
                d->core = core;
                d->paths_list_get_cb = paths_list_get_cb;
                d->paths_list_get_data = paths_list_get_data;
		d->goto_directory_cb = goto_directory_cb;
		d->goto_directory_data = goto_directory_data;
                d->command_name = STRDUP(command_name);
                d->toplevel = toplevel;
                d->verbose = TRUE;
                DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		break;

	      case EDV_MIME_TYPE_HANDLER_EDV_RECYCLE_BIN:
		command_name = "Recycle Bin";
                d = EDVOpenCBDataNew();
                d->core = core;
                d->paths_list_get_cb = paths_list_get_cb;
                d->paths_list_get_data = paths_list_get_data;
		d->goto_directory_cb = goto_directory_cb;
		d->goto_directory_data = goto_directory_data;
                d->command_name = STRDUP(command_name);
                d->toplevel = toplevel;
                d->verbose = TRUE;
                DO_ADD_MENU_ITEM_LABEL(command_name, NULL, d);
		break;
	    }
	    break;
	}

#undef DO_ADD_MENU_ITEM_LABEL
#undef DO_ADD_MENU_SEP

	return(menu);
}
