#include <gtk/gtk.h>

#include "cdialog.h"

#include "edv_mime_type.h"
#include "mime_types_list_win.h"
#include "endeavour2.h"
#include "edv_cb.h"
#include "edv_op.h"
#include "edv_mime_type_install.h"
#include "edv_utils_gtk.h"
#include "config.h"


gint EDVMimeTypeInstallWizard(
	edv_core_struct *core,
	const gint pos,
	edv_mime_type_class mt_class,
        const gchar *value,
	const gchar *type,
        const gchar *description,
	GtkWidget *toplevel
);

gint EDVMimeTypeInstall(
	edv_core_struct *core, edv_mime_type_struct *m,
	const gint pos,
	const gboolean interactive, const gboolean verbose,
	GtkWidget *toplevel
);


#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)


/*
 *	Queries the user to install a new MIME Type.
 *
 *	The pos specifies the index position in the MIME Types list
 *	to install the new MIME Type at. If pos is -1 then the new
 *	MIME Type will be appended.
 *
 *	Returns the index of the new installed MIME Type or one of the
 *	following error codes:
 *
 *	-1	General error.
 *	-2	Invalid value.
 *	-3	Systems error or memory allocation error.
 *	-4	User aborted.
 *	-5	Another operation is in progress.
 *	-7	Another MIME Type already exists with the same type.
 */
gint EDVMimeTypeInstallWizard(
	edv_core_struct *core,
	const gint pos,
	edv_mime_type_class mt_class,
        const gchar *value,
	const gchar *type,
        const gchar *description,
	GtkWidget *toplevel
)
{
	gint mt_num;
	edv_mime_type_struct *m;
	edv_mime_types_list_win_struct *lw;

	if(core == NULL)
	    return(-2);

	if(CDialogIsQuery())
	    return(-5);

	m = EDVMimeTypeNew(mt_class, value, type, description);
	if(m == NULL)
	    return(-3);

        /* Map the MIME Types window */
	EDVMapMIMETypesListWin(core, NULL, toplevel);

	/* Install the new MIME Type and select it on the MIME
	 * Types list
	 */
	mt_num = EDVMimeTypeInstall(
	    core, m,
	    pos,
	    FALSE,		/* Not interactive */
	    FALSE,		/* Not verbose */
	    toplevel
	);
	if(mt_num < 0)
	{
	    const gint error_code = mt_num;
	    gchar *s;
	    switch(error_code)
	    {
	      case -1:
		EDVPlaySoundError(core);
		EDVMessageError(
"Install MIME Type Failed",
"General error.",
		    NULL,
		    toplevel
		);
		break;
	      case -2:
		EDVPlaySoundError(core);
		EDVMessageError(
"Install MIME Type Failed",
"Invalid value.",
		    NULL,
		    toplevel
		);
		break;
	      case -3:
		EDVPlaySoundError(core);
		EDVMessageError(
"Install MIME Type Failed",
"Memory allocation error.",
		    NULL,
		    toplevel
		);
		break;
	      case -4:
		EDVPlaySoundWarning(core);
		EDVMessageWarning(
"Install MIME Type Canceled",
"Install MIME Type canceled.",
		    NULL,
		    toplevel
		);
		break;
	      case -5:
		EDVPlaySoundWarning(core);
		EDVMessageWarning(
"Install MIME Type Failed",
"Another operation is already in progress.",
		    NULL,
		    toplevel
		);
		break;
	      case -7:
		EDVPlaySoundWarning(core);
		s = g_strdup_printf(
"The MIME Type:\n\
\n\
    %s\n\
\n\
Already exists.",
		    type
		);
		EDVMessageWarning(
"Install MIME Type Failed",
		    s,
		    NULL,
		    toplevel
		);
		g_free(s);
		break;
	    }

	    return(error_code);
	}

	/* Edit the new MIME Type */
	lw = core->mimetype_listwin;
	EDVMimeTypesListWinEdit(lw, mt_num);

	return(mt_num);
}


/*
 *	Installs a new MIME Type.
 *
 *	The core specifies the core and the list of MIME Types to
 *	install the MIME Type to.
 *
 *	The m specifies the MIME Type to be installed. It will be
 *	transfered and therefore it should not be referenced again
 *	after this call.
 *
 *	The pos specifies the index position in the MIME Types list
 *	to install the new MIME Type at. If pos is -1 then the new
 *	MIME Type will be appended.
 *
 *	Returns the index of the new installed MIME Type or one of the
 *	following error codes:
 *
 *	-1	General error.
 *	-2	Invalid value.
 *	-3	Systems error or memory allocation error.
 *	-4	User aborted.
 *	-5	Another operation is in progress.
 *	-7	Another MIME Type already exists with the same type.
 */
gint EDVMimeTypeInstall(
	edv_core_struct *core, edv_mime_type_struct *m,
	const gint pos,
	const gboolean interactive, const gboolean verbose,
	GtkWidget *toplevel
)
{
	gint mt_num;
	edv_mime_types_list_win_struct *lw;

	if((core == NULL) || (m == NULL))
	{
	    EDVMimeTypeDelete(m);
	    return(-2);
	}

	lw = core->mimetype_listwin;

	/* Check if another MIME Type exists with the same type */
	if(!STRISEMPTY(m->type))
	{
	    gint i;
	    const edv_mime_type_struct *m2 = NULL;
	    for(i = 0; i < core->total_mimetypes; i++)
	    {
		m2 = core->mimetype[i];
		if(m2 == NULL)
		    continue;

		if(STRISEMPTY(m2->type))
		    continue;

		if(!g_strcasecmp(m2->type, m->type))
		    break;
	    }
	    /* Another MIME Type exists with the same type? */
	    if(i < core->total_mimetypes)
	    {
		if(!CDialogIsQuery() && interactive)
		{
		    gchar *buf;
		    if((m2 != NULL) ? (m2->description != NULL) : FALSE)
			buf = g_strdup_printf(
"Another MIME Type exists with the same type:\n\
\n\
    %s\n\
\n\
%s",
			    m->type, m2->description
			);
		    else
			buf = g_strdup_printf(
"Another MIME Type exists with the same type:\n\
\n\
    %s",
			    m->type
			);
		    EDVPlaySoundError(core);
		    EDVMessageError(
"Install MIME Type Failed",
			buf,
			NULL,
			toplevel
		    );
		    g_free(buf);
		}
		EDVMimeTypeDelete(m);
		return(-7);
	    }
	}

	/* Confirm install? */
	if(interactive)
	{
	    gint response;
	    gchar *buf;

	    if(CDialogIsQuery())
	    {
		EDVMimeTypeDelete(m);
		return(-5);
	    }

	    buf = g_strdup_printf(
"Install MIME Type:\n\
\n\
    %s\n\
\n\
%s",
		m->type, m->description
	    );
	    EDVPlaySoundQuestion(core);
	    CDialogSetTransientFor(toplevel);
	    response = CDialogGetResponse(
"Install MIME Type",
		buf,
"You are being asked if you want to install a new MIME Type.\n\
\n\
MIME Types are used for recognizing different kinds of file\n\
formats and determining how to handle them.\n\
\n\
For more information on MIME Types see Help->MIME Types",
		CDIALOG_ICON_INSTALL,
		CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO,
		CDIALOG_BTNFLAG_YES
	    );
	    CDialogSetTransientFor(NULL);
	    g_free(buf);
	    if(response != CDIALOG_RESPONSE_YES)
	    {
		EDVMimeTypeDelete(m);
		return(-4);
	    }
	}


	/* Append? */
	if((pos < 0) || (pos >= core->total_mimetypes))
	{
	    /* Allocate more pointers */
	    mt_num = MAX(core->total_mimetypes, 0);
	    core->total_mimetypes = mt_num + 1;
	    core->mimetype = (edv_mime_type_struct **)g_realloc(
		core->mimetype,
		core->total_mimetypes * sizeof(edv_mime_type_struct *)
	    );
	    if(core->mimetype == NULL)
	    {
		core->total_mimetypes = 0;
		EDVMimeTypeDelete(m);
		return(-3);
	    }

	    /* Set new MIME Type at appended position */
	    core->mimetype[mt_num] = m;
	}
	else
	{
	    gint i;

	    mt_num = pos;

	    /* Allocate more pointers */
	    core->total_mimetypes++;
	    core->mimetype = (edv_mime_type_struct **)g_realloc(
		core->mimetype,
		core->total_mimetypes * sizeof(edv_mime_type_struct *)
	    );
	    if(core->mimetype == NULL)
	    {
		core->total_mimetypes = 0;
		EDVMimeTypeDelete(m);
		return(-3);
	    }

	    /* Shift pointers */
	    for(i = core->total_mimetypes - 1; i > mt_num; i--)
		core->mimetype[i] = core->mimetype[i - 1];

	    /* Set the new MIME Type at the insert position */
	    core->mimetype[mt_num] = m;
	}


	/* Notify about the new MIME Type being added */
	EDVMimeTypeAddedEmit(core, mt_num, m);

	/* Us tge MIME Types List Window mapped? */
	if(EDVMimeTypesListWinIsMapped(lw))
	{
	    EDVMimeTypesListWinSetBusy(lw, TRUE);

	    /* Select the newly installed MIME Type */
	    EDVMimeTypesListWinSelect(lw, mt_num);

	    EDVMimeTypesListWinSetBusy(lw, FALSE);
	}

	return(mt_num);
}
